如何在 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.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
【讨论】:
我试过了,但我有一个小问题,第一个文本是从边框本身开始的,所以看起来不太好看有什么办法可以解决这个问题 @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 中使按钮具有圆形边框?的主要内容,如果未能解决你的问题,请参考以下文章