Swift iOS - 如何排列子层位置以匹配按钮文本的中心

Posted

技术标签:

【中文标题】Swift iOS - 如何排列子层位置以匹配按钮文本的中心【英文标题】:Swift iOS - How to line up a sublayer position to match the center of button text 【发布时间】:2018-11-08 10:35:21 【问题描述】:

我有一个文本按钮。我添加了一个红色背景 subLayer,并将 backgroundLayer 的宽度和高度设置为大于按钮文本。我尝试使用以下方法将背景层居中放置在按钮上:

backgroundLayer.position = button.center

它不是居中的。这是我得到的:

我知道我可以直接在按钮上设置背景颜色和cornerRadius,但是当我这样做时,红色背景会拥抱文本:

button.backgroundColor = UIColor.red
button.layer.cornerRadius = 10

我希望红色背景比文字更宽更高:

backgroundLayer.frame = CGRect(x: 0, y: 0, width: buttonTextSize.width + 10, height: buttonTextSize.height + 5

我会用 Photoshop 制作一个示例,但目前我面前没有 Photshop。这是我能找到的最接近的。这是来自 Vimeo 的按钮。他们没有使用文本,但 backgroundLayer 比按钮图像更宽更高,并且 backgroundLayer 的位置与按钮的 midX 和 midY 对齐:

如何让背景子图层的位置与按钮文字的中心对齐?

let button: UIButton = 
    let button = UIButton()
    button.translatesAutoresizingMaskIntoConstraints = false
    button.setTitle("Next", for: .normal)
    button.setTitleColor(UIColor.white, for: .normal)
    button.contentHorizontalAlignment = .center
    button.titleLabel?.font = UIFont.systemFont(ofSize: 23)
    return button
()

let backgroundLayer: CALayer = 
    let layer = CALayer()
    layer.backgroundColor = UIColor.red.cgColor
    layer.cornerRadius = 10
    return layer
()

override func viewDidLoad() 
    super.viewDidLoad()
    view.backgroundColor = UIColor.lightGray

    view.addSubview(button)
    button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true


override func viewWillLayoutSubviews() 
    super.viewWillLayoutSubviews()

    let buttonText = button.titleLabel?.text
    let buttonTextSize = (buttonText! as NSString).size(withAttributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 23.0)])

    // I added 10 points to the backgroundLayer's width and 5 points to the backgroundLayer's height so its wider then the text
    backgroundLayer.frame = CGRect(x: 0, y: 0, width: buttonTextSize.width + 10, height: buttonTextSize.height + 5)
    button.layer.insertSublayer(backgroundLayer, at: 0)

    backgroundLayer.position = button.center

【问题讨论】:

使用 backgroundLayer.frame = button.bounds 背景层比文字更宽更高:CGRect(x: 0, y: 0, width: buttonTextSize.width + 10, height: buttonTextSize.height + 5) @ReinierMelian 感谢您的帮助。我试过 backgroundLayer.frame = button.bounds 但没用。 @matt 我知道如何以常规方式进行操作,我可以使用 button.backgroundColor = UIColor.red。 ,button.layer.cornerRadius = 10。我刚刚进入 CALayers(以前从未深入使用过它们),我想知道为什么 CALayer 的位置不会与按钮的中心对齐 @matt 是的,但关键是 subLayer 比按钮的文本更宽更高。顺便说一句,我刚刚尝试过: backgroundLayer.position = CGPoint(x: button.bounds.midX, y: button.bounds.midY) 但我仍然无法得到它。感谢您对以下内容的澄清:“按钮的中心不是它的边界中心;它是它的框架中心。” 【参考方案1】:

马特赞成的答案是正确的。

他在 cmets 中向我指出了我最初做错的两件事。

    我尝试设置backgroundLayer.position = button.center。这是错误的,因为按钮的中心是基于框架的 center 而不是它的 bounds 中心。我应该设置 backgroundLayer.position 以匹配按钮边界的中心 我试图将 backgroundLayer 的位置设置为按钮在viewWillLayoutSubviews 的中心,他说按钮的边界尚不清楚,因此 backgroundLayer 没有任何信息可以作为其依据。我应该将代码添加到viewDidLayoutSubviews

这里是代码:

// 1. add the code to viewDidLayoutSubviews
override func viewDidLayoutSubviews() 
    super.viewDidLayoutSubviews()

    let text = button.titleLabel?.text
    let textSize = (text! as NSString).size(withAttributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 23.0)])

    backgroundLayer.frame = CGRect(x: 0, y: 0, width: textSize.width + 10, height: textSize.height + 5)
    button.layer.insertSublayer(backgroundLayer, at: 0)

    // 2. get the buttons bound's center by accessing it's midX and midY
    let buttonMidX = button.bounds.midX
    let buttonMidY = button.bounds.midY
    let buttonBoundsCenter = CGPoint(x: buttonMidX, y: buttonMidY)

    // 3. set the backgroundLayer's postion to the buttonBoundsCenter
    backgroundLayer.position = buttonBoundsCenter

它有效:

【讨论】:

感谢您的建议???【参考方案2】:

这是一个看起来像你想要的样子的按钮(当然你可以调整任何不适合你感觉的参数):

此按钮自动变为红色、圆角,并且比其文本大得多(即使按钮使用自动布局定位)。

这是通过子类实现的:

class MyRedButton : UIButton 
    override func layoutSubviews() 
        super.layoutSubviews()
        self.backgroundColor = .red
        self.layer.cornerRadius = 10
    
    override var intrinsicContentSize: CGSize 
        var sz = super.intrinsicContentSize
        sz.width += 30; sz.height += 30
        return sz
    

【讨论】:

以上是关于Swift iOS - 如何排列子层位置以匹配按钮文本的中心的主要内容,如果未能解决你的问题,请参考以下文章

UIStackView 在 tableView Cell didSet 中添加排列子视图

html如何做点击按钮出现一个层,点击另外一个按钮在同一位置出现另外一个层,原层隐藏的效果?

IOS/Swift:检查按钮图像以切换按钮图像

iOS Swift - 如何以编程方式为所有按钮分配默认操作

ios - 如何使用ios swift中的自动布局以编程方式将两个标签并排放置在中心位置?

Swift,iOS - 单击以显示文本字段时按钮向上移动?然后搬回去?