Как сделать так, чтобы кнопка в Swift имела закругленную границу?

176

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

Теги:
uibutton

12 ответов

405
Лучший ответ

Используйте 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
    Я пробовал это, но у меня есть небольшая проблема, первый текст начинается с самой границы, так что не очень хорошо выглядит, есть ли способ решить эту проблему
  • 1
    @ vinbhai4u Попробуйте использовать titleEdgeInsets .
Показать ещё 12 комментариев
32

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

С помощью IBDesignable мы можем добавить дополнительные параметры в Inspector Interface 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)
        }
    }
}

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

Изображение 1778

  • 2
    Это более или менее копия ответа Хамзы Газуани ниже.
  • 0
    Когда я использую вышеупомянутое решение для boarderColor, который не удалось построить в interfacebuilder, я использую приведенный ниже код, но я добьюсь успеха, если использовал didset, а не set и get. @IBInspectable var borderColor: UIColor = .red {// didSet {// layer.borderColor = borderColor.cgColor //} set {guard let uiColor = newValue else {return} layer.borderColor = uiColor.cgColor} get {guard let color = layer.borderColor else {return nil} return UIColor (cgColor: color)}}
Показать ещё 1 комментарий
21

Я создал простую подструктуру UIButton, которая использует 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/questions/26542035/create-uiimage-with-solid-color-in-swift

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

12

Этот класс основан на всех комментариях и предложениях в ответах, а также может быть назначаемым непосредственно из 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, если не ошибаюсь. Я обновил код.
Показать ещё 1 комментарий
8

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

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

  • 1
    Это действительно работает, но не специфично для Swift. Вопрос прямо спрашивает, как достичь желаемого эффекта с помощью Swift, а не с помощью раскадровки или тому подобного.
  • 1
    Мой ответ был направлен не ОП, а другим читателям, которые столкнулись с моей проблемой. и только найдя этот пост смогли решить проблему. По моему мнению и опыту, ответы не обязательно должны быть точно такими, какие задал ФП, поскольку они связаны с ним и дают дополнительную информацию, полезную для читателей. Голосуя за такие ответы, вы отказываетесь от полезных ответов.
Показать ещё 3 комментария
2
   @IBOutlet weak var yourButton: UIButton! {
        didSet{
            yourButton.backgroundColor = .clear
            yourButton.layer.cornerRadius = 10
            yourButton.layer.borderWidth = 2
            yourButton.layer.borderColor = UIColor.white.cgColor
        }
    }
2

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

посетите этот репортаж github для справки

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
    Кто бы это ни отрицал, ты даже пытался работать таким образом?
  • 0
    Почему отрицательный голос? Кажется, это работает и очень чисто.
Показать ещё 2 комментария
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 }
    }
}

Обновить

В этой ссылке вы можете найти пример с полезностью протокола Traceable

Изображение 1779

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

Попробуйте эту кнопку границу с закругленными углами

anyButton.backgroundColor = .clear

anyButton.layer.cornerRadius = anyButton.frame.height / 2

anyButton.layer.borderWidth = 1

anyButton.layer.borderColor = UIColor.black.cgColor
0

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

  • 0
    Пожалуйста, используйте правильную пунктуацию, никто не хочет читать это ...
  • 0
    @returntrue Что не понятно?
0
@IBOutlet weak var button: UIButton!

...

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

button.layer.cornerRadius = 5
  • 0
    Это не добавляет ничего нового, кажется.
-3

Вы можете настроить свою кнопку и добавить IBInspectable var, чтобы установить ее из StoryBoard "Attribute Inspector". Ниже я записываю этот код.

@IBDesignable
class BHButton: UIButton {

    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

    @IBInspectable lazy var isRoundRectButton : Bool = false

    @IBInspectable public var cornerRadius : CGFloat = 0.0 {
        didSet{
            setUpView()
        }
    }

    @IBInspectable public var borderColor : UIColor = UIColor.clear {
        didSet {
            self.layer.borderColor = borderColor.cgColor
        }
    }

    @IBInspectable public var borderWidth : CGFloat = 0.0 {
        didSet {
            self.layer.borderWidth = borderWidth
        }
    }

    //  MARK:   Awake From Nib

    override func awakeFromNib() {
        super.awakeFromNib()
        setUpView()
    }

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        setUpView()
    }

    func setUpView() {
        if isRoundRectButton {
            self.layer.cornerRadius = self.bounds.height/2;
            self.clipsToBounds = true
        }
        else{
            self.layer.cornerRadius = self.cornerRadius;
            self.clipsToBounds = true
        }
    }

}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню