2014-11-16 2 views
142

Я создаю приложение, использующее быструю версию последней версии Xcode 6, и хотел бы знать, как я могу изменить свою кнопку, чтобы она могла иметь закругленную границу, которую я мог бы при необходимости настроить. Как только это будет сделано, как я могу изменить цвет самой границы, не добавляя к ней фона? Другими словами, мне нужна слегка закругленная кнопка без фона, только граница 1pt определенного цвета.Как сделать кнопку с закругленной границей в Swift?

ответ

342

button.layer.cornerRadius, button.layer.borderColor и button.layer.borderWidth. Обратите внимание, что borderColor требует CGColor, так что можно сказать (Swift 3/4):

button.backgroundColor = .clear 
button.layer.cornerRadius = 5 
button.layer.borderWidth = 1 
button.layer.borderColor = UIColor.black.cgColor 
+2

Я попытался это, но у меня есть небольшая проблема первый текст начинается с самой границы, поэтому его не что хороший взгляд есть ли способ решить это – vinbhai4u

+1

@ vinbhai4u Попробуйте использовать 'titleEdgeInsets'. –

+1

, который работает как очарование спасибо :) – vinbhai4u

15

Я создал простой UIButton sublcass, который использует tintColor для его текста и границы цветов и при выделении изменения его предысторию tintColor.

class BorderedButton: UIButton { 

required init?(coder aDecoder: NSCoder) { 
    super.init(coder: aDecoder) 
    layer.borderWidth = 1.0 
    layer.borderColor = tintColor.CGColor 
    layer.cornerRadius = 5.0 
    clipsToBounds = true 
    contentEdgeInsets = UIEdgeInsets(top: 8, left: 8, bottom: 8, right: 8) 
    setTitleColor(tintColor, forState: .Normal) 
    setTitleColor(UIColor.whiteColor(), forState: .Highlighted) 
    setBackgroundImage(UIImage(color: tintColor), forState: .Highlighted) 
} 
} 

Это делает использование расширения UIImage, который создает изображение с цветом, я обнаружил, что код здесь: https://stackoverflow.com/a/33675160

Это работает лучше всего, когда установлен тип пользовательского в интерфейсе строителя, как тип системы по умолчанию немного изменяет цвета, когда кнопка подсвечивается.

10

Этот класс основан на всех комментариях и предложениях в ответах, а также может быть назначаемым непосредственно из xcode. Скопируйте в свой проект и вставьте любой UIButton и измените использование пользовательского класса, теперь просто выберите цвет границы или фона из xcode для нормальных и/или выделенных состояний.

// 
// RoundedButton.swift 
// 

import UIKit 

@IBDesignable 
class RoundedButton:UIButton { 

    @IBInspectable var borderWidth: CGFloat = 0 { 
     didSet { 
      layer.borderWidth = borderWidth 
     } 
    } 
    //Normal state bg and border 
    @IBInspectable var normalBorderColor: UIColor? { 
     didSet { 
      layer.borderColor = normalBorderColor?.CGColor 
     } 
    } 

    @IBInspectable var normalBackgroundColor: UIColor? { 
     didSet { 
      setBgColorForState(normalBackgroundColor, forState: .Normal) 
     } 
    } 


    //Highlighted state bg and border 
    @IBInspectable var highlightedBorderColor: UIColor? 

    @IBInspectable var highlightedBackgroundColor: UIColor? { 
     didSet { 
      setBgColorForState(highlightedBackgroundColor, forState: .Highlighted) 
     } 
    } 


    private func setBgColorForState(color: UIColor?, forState: UIControlState){ 
     if color != nil { 
      setBackgroundImage(UIImage.imageWithColor(color!), forState: forState) 

     } else { 
      setBackgroundImage(nil, forState: forState) 
     } 
    } 

    override func layoutSubviews() { 
     super.layoutSubviews() 

     layer.cornerRadius = layer.frame.height/2 
     clipsToBounds = true 

     if borderWidth > 0 { 
      if state == .Normal && !CGColorEqualToColor(layer.borderColor, normalBorderColor?.CGColor) { 
       layer.borderColor = normalBorderColor?.CGColor 
      } else if state == .Highlighted && highlightedBorderColor != nil{ 
       layer.borderColor = highlightedBorderColor!.CGColor 
      } 
     } 
    } 

} 

//Extension Required by RoundedButton to create UIImage from UIColor 
extension UIImage { 
    class func imageWithColor(color: UIColor) -> UIImage { 
     let rect: CGRect = CGRectMake(0, 0, 1, 1) 
     UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 1), false, 1.0) 
     color.setFill() 
     UIRectFill(rect) 
     let image: UIImage = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 
     return image 
    } 
} 
+1

Почему импортирования 'Foundation' при импорте' UIKit' действительно хватает? –

+0

@returntrue Да, вы правы, Foundation не требуется, я пришел из исходного базового шаблона xcode, если я не ошибаюсь. Я обновил код. – le0diaz

+0

Единственное, что это сделает круговую кнопку все время. Возможно, вы также можете добавить свойство углового радиуса, чтобы исправить это. – Andreas777

7

Основываясь на ответе @returntrue, мне удалось реализовать его в Interface Builder.

Чтобы получить кнопки круглых углов с помощью Interface Builder добавить ключ Path = "layer.cornerRadius" с Type = "Number" и Value = "10" (или другим значением по мере необходимости) в «User Defined RunTime Attribute» из Identity Inspector кнопки.

+1

Это действительно работает, но не зависит от Swift. Вопрос явно задает вопрос о том, как добиться желаемого эффекта, используя Swift, а не с помощью раскадровки или тому подобного. –

+1

Мой ответ был направлен не на ОП, а на других читателей, столкнувшихся с моей проблемой. и только, найдя этот пост, смогли решить проблему. По моему мнению и опыту, ответы не соответствуют именно тому, что задал ОП, если они связаны с ним и дают дополнительную информацию, которая полезна читателям. Путем голосования таких ответов вы отговариваете полезные ответы. – Zvi

+1

Хотя это в целом верно - особенно для широких вопросов - этот вопрос ясен по своему характеру. Существует множество вопросов, которые требуют явного решения с помощью раскадровки, и, если возможно, читатели хотели иметь решение, использующее раскадровку, добавление «раскадровки» в поисковые термины Google достаточно, чтобы показать эти вопросы. Я не говорю, что ваш ответ плох, но скорее не в том месте. –

-1

Я думаю, что самый простой и чистый способ - использовать протокол, чтобы избежать наследования и повторения кода. Вы можете изменить эти свойства непосредственно из раскадровки

protocol Traceable { 
    var cornerRadius: CGFloat { get set } 
    var borderColor: UIColor? { get set } 
    var borderWidth: CGFloat { get set } 
} 

extension UIView: Traceable { 

    @IBInspectable var cornerRadius: CGFloat { 
     get { return layer.cornerRadius } 
     set { 
      layer.masksToBounds = true 
      layer.cornerRadius = newValue 
     } 
    } 

    @IBInspectable var borderColor: UIColor? { 
     get { 
      guard let cgColor = layer.borderColor else { return nil } 
      return UIColor(cgColor: cgColor) 
     } 
     set { layer.borderColor = newValue?.cgColor } 
    } 

    @IBInspectable var borderWidth: CGFloat { 
     get { return layer.borderWidth } 
     set { layer.borderWidth = newValue } 
    } 
} 

Update

В этом link вы можете найти пример с полезностью ПРОСЛЕЖИВАЕМОГО протокола

enter image description here

+2

Вам здесь не нужен протокол.Без него отлично работает. –

+1

Привет, @returntrue, я не знаю, почему вы отрицаете мой ответ ... Я думаю, что вы этого не поняли, я приглашаю вас посмотреть эту сессию: https://developer.apple.com/videos/play/wwdc2015/408/ Зачем использовать протокол? протокол позволяет больше гибкости, я могу иметь реализацию по умолчанию и т. д. Мой ответ позволяет редактировать эти свойства в раскадровке, и мне не нужно повторять код или подкласс любого класса . Ваш ответ верный, но здесь я поделился другим способом сделать это Вы публикуете все остальные ответы, вы должны помнить, что Stackoverflow предназначен для обмена нашими знаниями до получения репутации. –

+2

Правильно, ваш код позволяет все перечисленные вами вещи. НО, поскольку UIView является суперклассом всех элементов пользовательского интерфейса, расширение UIView достаточно для выполнения задания. Протокол Traceable не требуется никоим образом и не дает никаких улучшений (поскольку он просто переводит UIView - только UIViews и его подклассы прослеживаются). –

8

Чтобы сделать это работа в раскадровке (инспектор интерфейса Builder)

С помощью IBDesignable мы можем добавить дополнительные опции в инсталлятор интерфейса Builder для UIButton и настроить их на раскадровке. Сначала добавьте следующий код в свой проект.

@IBDesignable extension UIButton { 

    @IBInspectable var borderWidth: CGFloat { 
     set { 
      layer.borderWidth = newValue 
     } 
     get { 
      return layer.borderWidth 
     } 
    } 

    @IBInspectable var cornerRadius: CGFloat { 
     set { 
      layer.cornerRadius = newValue 
     } 
     get { 
      return layer.cornerRadius 
     } 
    } 

    @IBInspectable var borderColor: UIColor? { 
     set { 
      guard let uiColor = newValue else { return } 
      layer.borderColor = uiColor.cgColor 
     } 
     get { 
      guard let color = layer.borderColor else { return nil } 
      return UIColor(cgColor: color) 
     } 
    } 
} 

Затем просто установите атрибуты кнопок на раскадровке.

enter image description here

+0

Это более или менее копия ответа ниже Хамза Газуани. –

+0

, когда я использую вышеупомянутое решение для boarderColor, оно не получилось в интерфейсе, я использую приведенный ниже код, но я успешно, если я использовал didset, а не устанавливал и получал. @IBInspectable вар BorderColor: UIColor = .red { // didSet { // layer.borderColor = borderColor.cgColor //} множество { охранник пусть UIColor = новое_значение еще {возвращение} layer.borderColor = uiColor.cgColor } прибудет { охранника пусть цвет = layer.borderColor еще {возвращение ноль} возвращение UIColor (cgColor: цвет) }} –

2

Вы можете использовать этот подкласс UIButton настроить UIButton в соответствии с вашими потребностями.

visit this github repo for reference

class RoundedRectButton: UIButton { 

    var selectedState: Bool = false 

    override func awakeFromNib() { 
     super.awakeFromNib() 
     layer.borderWidth = 2/UIScreen.main.nativeScale 
     layer.borderColor = UIColor.white.cgColor 
     contentEdgeInsets = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5) 
    } 


    override func layoutSubviews(){ 
     super.layoutSubviews() 
     layer.cornerRadius = frame.height/2 
     backgroundColor = selectedState ? UIColor.white : UIColor.clear 
     self.titleLabel?.textColor = selectedState ? UIColor.green : UIColor.white 
    } 

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { 
     selectedState = !selectedState 
     self.layoutSubviews() 
    } 
} 
+0

кто downvoted это, сделал и даже попытаться работать таким образом ??? просто не теряйте время downvoting –

+0

Почему downvote? это, похоже, работает и очень чисто. – ColdGrub1384

+0

@ ColdGrub1384 точно :) –

0
@IBOutlet weak var button: UIButton! 

...

Я думаю, что для радиуса достаточно только этот параметр:

button.layer.cornerRadius = 5 
+0

Это не добавляет ничего нового, похоже. –

0
@IBOutlet weak var yourButton: UIButton! { 
     didSet{ 
      yourButton.backgroundColor = .clear 
      yourButton.layer.cornerRadius = 10 
      yourButton.layer.borderWidth = 2 
      yourButton.layer.borderColor = UIColor.white.cgColor 
     } 
    } 
Смежные вопросы