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

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

【问题讨论】:

    标签: swift uibutton


    【解决方案1】:

    UIBuilder 爱好者的解决方案:

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

    2. 点击“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 的要求,只要它们与它相关并提供对读者有用的额外信息。通过对此类答案投反对票,您会阻碍有用的答案。
                  • 虽然这通常是正确的 - 特别是对于广泛的问题 - 这个问题的性质很明确。存在许多通过故事板要求明确解决方案的问题,如果可能的读者想要一个利用故事板的解决方案,那么在谷歌搜索词中添加“故事板”就足以显示这些问题。我不是说你的回答不好,而是说错了地方。
                  • 因为我发现这篇文章最能解决我的问题,所以我把它贴在这里。走你的路意味着我应该写一篇新帖子并回复我的帖子,在我看来,这似乎有点矫枉过正。
                  • 我发现那些问题似乎比这个问题更能解决您的问题:stackoverflow.com/questions/12301256; stackoverflow.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 为什么使用协议?该协议允许更大的灵活性,我可以有默认实现等如果你对所有其他答案投了反对票,你应该记住 Stackoverflow 是为了在赢得声誉之前分享我们的知识
                  • 正确,您的代码允许您列出所有这些内容。但是,由于 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://stackoverflow.com/a/33675160

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

                  【讨论】:

                    猜你喜欢
                    • 2020-03-14
                    • 1970-01-01
                    • 2023-01-28
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-03-04
                    • 1970-01-01
                    相关资源
                    最近更新 更多