如何在Swift中使按钮的边框变为圆形?


232

我正在最新版本的Xcode 6中使用swift构建应用程序,并且想知道如何修改按钮,使其具有圆角边框,如有需要,我可以自行调整。完成后,如何在不添加边框的情况下更改边框本身的颜色?换句话说,我想要一个略带圆形的按钮,没有背景,只有一个1pt边框的某种颜色。

Answers:


528

使用button.layer.cornerRadiusbutton.layer.borderColorbutton.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
我尝试过这个问题,但是我有一个小问题,第一个文本是从边框本身开始的,因此,它看起来不是那么好看
吗?

2
@ vinbhai4u尝试使用titleEdgeInsets
返回真实

我们如何使方框大于按钮文本?
2015年

创建一个按钮可以参考的插座
Jobs

我想像这样使用它,但不起作用:( UIButton.appearance()。layer.cornerRadius = 4
MR

65

在情节提要中执行此工作(Interface Builder检查器)

借助IBDesignable,我们可以为Interface Builder Inspector添加更多选项,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)
        }
    }
}

然后只需在情节提要上设置按钮的属性。

在此处输入图片说明


4
这或多或少是以下Hamza Ghazouani答案的副本。
返回真实

当我将上述解决方案用于boarderColor时,它在interfacebuilder中构建失败,我使用以下代码,但是如果我使用didset而不是set and get,则我可以成功。@IBInspectable var borderColor:UIColor = .red {// didSet {// layer.borderColor = borderColor.cgColor // //设置{保护let uiColor = newValue else {返回} layer.borderColor = uiColor.cgColor} get {保护let color = layer.borderColor else {return nil} return UIColor(cgColor:color)}}
Amr Angry

1
哇,像魔术!谢谢!Google员工-确保将这段代码片段完全放在要放入文件的最后一个大括号之外–这段代码片段不应位于任何类或函数之内
velkoon

24

我创建了一个简单的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

当在界面生成器中设置为“自定义”时,它的效果最佳,因为突出显示按钮时,默认的系统类型会稍微修改颜色。


13

该类基于答案中的所有注释和建议,也可以直接从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
为什么在导入FoundationUIKit就足够了?
返回真实

@returntrue是的,您是对的,不需要Foundation,如果我没记错的话,我来自原始的xcode基本模板。我更新了代码。
le0diaz '16

唯一的是,这将使按钮始终保持圆形。也许您也可以添加一个转角半径属性来解决此问题。
Andreas777 '17

10

基于@returntrue答案,我设法在Interface Builder中实现了它。

要使用Interface Builder获取圆角按钮,请在按钮的“ ”中添加Path = "layer.cornerRadius"带有Type = "Number"和的Key Value = "10"(或其他必要的值)。User Defined RunTime AttributeIdentity Inspector


1
确实可以,但是不是特定于Swift的。该问题明确询问如何通过使用Swift而不是通过情节提要板等来实现所需的效果。
返回真实

2
我的回答不是针对OP,而是针对其他遇到我问题的读者。而且只有找到这篇文章才能解决问题。以我的观点和经验,答案并不完全是OP所要求的,只要它们与OP相关并且能提供对读者有用的额外信息即可。通过对这样的答案投反对票,您会阻止有用的答案。
Zvi

1
虽然这通常是正确的-特别是对于广泛的问题-这个问题的性质很明显。存在许多问题,要求通过情节提要提供明确的解决方案,并且,如果可能,读者希望使用情节提要提供解决方案,然后在Google搜索字词中添加“故事提要”即可显示这些问题。我并不是说您的答案是错误的,而是在错误的地方。
返回真实

由于我发现此帖子与解决我的问题最接近,因此我将其发布在这里。走自己的路,意味着我应该写一篇新文章并回答我的文章,在我看来,这似乎有点过分。
Zvi

1
我发现那些问题似乎比这个问题更能解决您的问题:stackoverflow.com/questions/12301256 ; stackoverflow.com/questions/20477990
返回true

6

您可以根据需要使用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()
    }
}

谁对此投票否决,您甚至尝试过这种方式吗?只是不要浪费您的时间投票
Nikesh Jha

为什么要投票?这似乎可行并且非常干净。
ColdGrub1384

@ ColdGrub1384正好:)
Nikesh Jha

3

我认为最简单,最干净的方法是使用协议来避免继承和代码重复。您可以直接从情节提要更改此属性

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 }
    }
}

更新资料

在此链接中,您可以找到带有可跟踪协议实用程序的示例。

在此处输入图片说明


2
您实际上不需要这里的协议。没有它,可以完全正常工作。
返回真实

2
@returntrue,您好,我不知道您为什么对我的回答不满意...我认为您不明白,我邀请您观看此会议:developer.apple.com/videos/play/wwdc2015/408为什么使用协议?该协议可以提供更大的灵活性,我可以使用默认实现,等等。我的答案允许在情节提要中编辑此属性,并且不需要重复代码或为任何类创建子类您的答案是正确的,但在此我分享了另一种方法它您否决了所有其他答案,您应该记住,Stackoverflow是在赢得声誉之前分享我们的知识
Hamza

2
正确,您的代码允许您列出所有这些内容。但是,由于UIView是所有UI元素的超类,因此您的UIView扩展足以完成这项工作。协议Traceable不需要任何方式,也不会产生任何改进(因为它只是转换为UIView-只有UIViews及其子类是可跟踪的)。
返回真实

1
@returntrue,您好,在这个用例中,您可能是对的,我们不需要协议,但是有了它,我们可以有更大的灵活性,例如,我们可以添加默认值以应用,并且仅适用于UIImageView和UIButton,将使用以下示例更新我的答案:)
Hamza

1
为角半径或边框颜色等属性应用默认值实际上没有任何意义。这些值应该以有意义的方式分别应用于UI 中的每个视图实例。
返回真实

3
   @IBOutlet weak var yourButton: UIButton! {
        didSet{
            yourButton.backgroundColor = .clear
            yourButton.layer.cornerRadius = 10
            yourButton.layer.borderWidth = 2
            yourButton.layer.borderColor = UIColor.white.cgColor
        }
    }

1

顺便提一下,请确保您的按钮不是故事板上任何自定义类的子类,在这种情况下,您的代码最好的位置应该在自定义类中,这是因为如果您的按钮是默认类的子类,则自原因代码仅在自定义类中起作用UIButton类及其出口,希望这可以帮助任何人怀疑为什么角落收音机不能从代码应用于我的按钮。



0

尝试此 带有圆角的按钮边框

anyButton.backgroundColor = .clear

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

anyButton.layer.borderWidth = 1

anyButton.layer.borderColor = UIColor.black.cgColor

是的,但是它引入了使用动态的cornerRadius的想法,我不认为它是简单地复制粘贴的。
benc

0
import UIKit

@IBDesignable
class RoundedButton: UIButton {
    
    @IBInspectable var cornerRadius: CGFloat = 8
    @IBInspectable var borderColor: UIColor? = .lightGray
    
    override func draw(_ rect: CGRect) {
        layer.cornerRadius = cornerRadius
        layer.masksToBounds = true
        layer.borderWidth = 1
        layer.borderColor = borderColor?.cgColor
        
    }
    
    
}

-1

您可以子类化UIButton并向其中添加@IBInspectable变量,以便可以通过StoryBoard“属性检查器”配置自定义按钮参数。下面我写下该代码。

@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
        }
    }

}

-1

我认为这是简单的形式

        Button1.layer.cornerRadius = 10(Half of the length and width)
        Button1.layer.borderWidth = 2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.