如何在 Swift 中使按钮具有圆形边框?

Posted

技术标签:

【中文标题】如何在 Swift 中使按钮具有圆形边框?【英文标题】:How can I make a button have a rounded border in Swift? 【发布时间】:2015-01-13 16:35:05 【问题描述】:

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

【问题讨论】:

【参考方案1】:

UIBuilder 爱好者的解决方案:

    选中 UIButton 的“属性检查器”窗口中的“剪辑到边界”复选框。 [见下图1]

    点击“Identity Inspector”,然后点击“+”符号输入一个新的 Key Path:layer.cornerRadius、Number、8(或 16 等...)。 [见下图2]

图 1:Clip to Bounds 复选框

图 2:关键路径代码...

图 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
    

【讨论】:

【参考方案3】:

我认为这是简单的形式

Button1.layer.cornerRadius = 10(Half of the length and width)
Button1.layer.borderWidth = 2

【讨论】:

【参考方案4】:

UIButton圆角边框的全局方法

class func setRoundedBorderButton(btn:UIButton)

   btn.layer.cornerRadius = btn.frame.size.height/2
   btn.layer.borderWidth = 0.5
   btn.layer.borderColor = UIColor.darkGray.cgColor

【讨论】:

【参考方案5】:
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
        
    
    
    

【讨论】:

【参考方案6】:

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

@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
        
    


【讨论】:

【参考方案7】:

试试这个 圆角按钮边框

anyButton.backgroundColor = .clear

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

anyButton.layer.borderWidth = 1

anyButton.layer.borderColor = UIColor.black.cgColor

【讨论】:

是的,但它引入了使用动态角半径的想法,我不认为它只是简单的复制和粘贴。【参考方案8】:

除了提示,请确保您的按钮不是故事板中任何自定义类的子类,在这种情况下,您的代码最佳位置应该在自定义类中,如果您的按钮是子类,则自因代码只能在自定义类之外工作默认的 UIButton 类和它的出口,希望这可以帮助任何人想知道为什么角落收音机不适用于我的代码按钮。

【讨论】:

【参考方案9】:
@IBOutlet weak var button: UIButton!

...

我认为对于半径来说这个参数就足够了:

button.layer.cornerRadius = 5

【讨论】:

这似乎没有添加任何新内容。【参考方案10】:

您可以使用 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()
    

【讨论】:

无论谁投了反对票,你有没有尝试过这样工作???只是不要浪费你的时间投反对票 为什么要投反对票?这似乎有效并且非常干净。 @ColdGrub1384 完全正确 :)【参考方案11】:

使用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

【讨论】:

我试过了,但我有一个小问题,第一个文本是从边框本身开始的,所以看起来不太好看有什么办法可以解决这个问题 @vinbhai4u 尝试使用titleEdgeInsets 如何让框比按钮文字大? 为按钮创建一个出口来引用它 我想像这样使用它但不起作用:( UIButton.appearance().layer.cornerRadius = 4【参考方案12】:

根据@returntrue 的回答,我设法在 Interface Builder 中实现了它。

要使用 Interface Builder 获得圆角按钮,请在按钮的 Identity Inspector 的“User Defined RunTime Attribute”中添加带有 Type = "Number"Value = "10"(或其他需要的值)的键 Path = "layer.cornerRadius"

【讨论】:

这确实有效,但不是 Swift 特有的。该问题明确询问如何通过使用 Swift 而不是使用故事板等来达到预期的效果。 我的回答不是针对 OP,而是针对其他面临我问题的读者。只有找到这个帖子才能解决问题。根据我的观点和经验,答案并不完全符合 OP 的要求,只要它们与它相关并提供对读者有用的额外信息。通过对此类答案投反对票,您会阻碍有用的答案。 虽然这通常是正确的 - 特别是对于广泛的问题 - 这个问题的性质很明确。存在许多通过故事板要求明确解决方案的问题,如果可能的读者想要一个利用故事板的解决方案,那么在谷歌搜索词中添加“故事板”就足以显示这些问题。我不是说你的回答不好,而是说错了地方。 因为我发现这篇文章最能解决我的问题,所以我把它贴在这里。走你的路意味着我应该写一篇新帖子并回复我的帖子,在我看来,这似乎有点矫枉过正。 我发现那些问题似乎比这个问题更能解决您的问题:***.com/questions/12301256; ***.com/questions/20477990【参考方案13】:

在故事板中完成这项工作(Interface Builder Inspector)

IBDesignable 的帮助下,我们可以为UIButton 添加更多选项到Interface Builder Inspector 并在故事板上调整它们。首先,将以下代码添加到您的项目中。

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

然后简单地设置故事板上按钮的属性。

【讨论】:

这或多或少是 Hamza Ghazouani 下面答案的副本。 当我将上述解决方案用于它在 interfacebuilder 中构建失败的 boarderColor 时,我使用下面的代码,但如果我使用 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) 哇,就像魔术一样!谢谢! Google 员工——确保将这段代码 sn-p 完全放在要放置它的文件中的最后一个花括号之外——代码 sn-p 不应位于任何类或函数中【参考方案14】:

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

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 
    

更新

在这个link你可以找到一个使用Traceable协议的例子

【讨论】:

这里不需要协议。没有它完全可以正常工作。 嗨@returntrue,我不知道你为什么不赞成我的回答......我想你没有理解它,我邀请你观看这个会话:developer.apple.com/videos/play/wwdc2015/408 为什么使用协议?该协议允许更大的灵活性,我可以有默认实现等如果你对所有其他答案投了反对票,你应该记住 *** 是为了在赢得声誉之前分享我们的知识 正确,您的代码允许您列出所有这些内容。但是,由于 UIView 是所有 UI 元素的超类,因此您的 UIView 扩展足以完成这项工作。 Traceable 协议在任何方面都不是必需的,也不会产生任何改进(因为它只是转换为 UIView - 只有 UIView 及其子类是可跟踪的)。 嗨@returntrue,你在这个用例中是对的,可能是,我们不需要协议,但是有了它我们有更多的灵活性,例如,我们可以添加默认值来应用和仅适用于 UIImageView 和 UIButton,我将用这个例子更新我的答案:) 对角半径或边框颜色等属性应用默认值并没有什么意义。这些值应该以有意义的方式单独应用于 UI 中的每个视图实例。【参考方案15】:

这个类基于答案中的所有 cmets 和建议,也可以直接从 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
    

【讨论】:

为什么在导入UIKit 时导入Foundation 真的就足够了? @returntrue 是的,你是对的,Foundation 不是必需的,如果我没记错的话,我来自原始的 xcode 基本模板。我更新了代码。 唯一的事情是,这将使按钮一直循环。也许你也可以添加一个圆角半径属性来解决这个问题。【参考方案16】:

我创建了一个简单的 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://***.com/a/33675160

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

【讨论】:

以上是关于如何在 Swift 中使按钮具有圆形边框?的主要内容,如果未能解决你的问题,请参考以下文章

带背景图像按钮的圆形边框swift

如何在 Flutter 中使我的单选按钮完全填充活动颜色的颜色而没有白色边框?

Swift Left Side只有带边框的圆形按钮

如何在 Xcode 中使元素具有百分比宽度

如何在 Swift 中创建一个圆形按钮? [关闭]

如何在图像视图周围制作圆形边框