【问题标题】:Swift - Custom UIButton Title Not ShowingSwift - 自定义 UIButton 标题不显示
【发布时间】:2021-09-21 22:11:05
【问题描述】:

我想创建不会重叠的六角形按钮,如果它们以“蜂窝”方式显示,并且只有正确的按钮才能被选中。我找到了掩码UIView here 的子类,并将它用于我的 UIButton 类来进行掩码。效果很好!

当我在视图中生成按钮时,按钮标题不可见。研究表明我需要使用 super.layoutSubviews() 能够显示标题的文本。我的打印方法显示标题已正确填充,并且与另一个对象类对应,但无论如何,标题都不会显示。预期标题为“H”,打印日志显示标题存在于第一个按钮中:

Getting category: Category(date: 2021-07-11 10:29:45 +0000, categoryID: "C1", categoryTitle: "Home", shortTitle: "H", categoryColor: UIExtendedSRGBColorSpace   0.403922 0.643137 0.921569 1, isDefault: false)
setupProperties short title: H
Short button title: H
Button Title: Optional("H")
Getting category: Category(date: 2021-07-11 10:15:50 +0000, categoryID: "C2", categoryTitle: "", shortTitle: "", categoryColor: UIExtendedSRGBColorSpace 0.960784 0.960784 0.960784 1, isDefault: true)
setupProperties short title: 
Short button title: 
Button Title: nil

我什至尝试在 UIButton 子视图中添加另一个标签,并以相同的方法将此标签放在前面,但它也不会显示。

是否有另一种方法可以强制自定义按钮显示标题文本,或者我是否必须创建 UILabel,标题与按钮的位置相同,并将其放置在按钮上方的图层中?这种方法不是首选...

是不是因为 UIButton 被多边形遮住了?

六角按钮类:

class HexaButton: UIButton {

var path: UIBezierPath!
var category: Category!


init(cat: Category) {
    super.init(frame: CGRect())
    self.category = cat
    self.setupProperties()
    //self.layoutSubviews()
}

required init?(coder: NSCoder) {
    super.init(coder: coder)
    self.setupProperties()
    //self.layoutSubviews()
    fatalError("init(coder:) has not been implemented")
}

override func awakeFromNib() {
    addTarget(self, action: #selector(touchDown), for: .touchDown)
    self.setupProperties()
    //self.layoutSubviews()
}

private func setupProperties(){
    self.titleLabel?.font = UIFont.boldSystemFont(ofSize: 10)
    self.setTitleColor(UIColor.white, for: .normal)
    self.setTitle(category.shortTitle, for: .normal)
    
    print("setupProperties short title: \(category.shortTitle)")

}

override func layoutSubviews() {
    super.layoutSubviews()
    self.titleLabel?.font = UIFont.boldSystemFont(ofSize: 10)
    self.setTitleColor(UIColor.white, for: .normal)
    self.setTitle(category.shortTitle, for: .normal)
}

override func draw(_ rect: CGRect) {
  
    let lineWidth: CGFloat = 5
    path = self.roundedPolygonPath(rect: self.bounds, lineWidth: lineWidth, sides: 6, cornerRadius: 10, rotationOffset: CGFloat(.pi / 2.0))

    let shapeLayer = CAShapeLayer()
    shapeLayer.strokeColor = category.categoryColor.cgColor
    shapeLayer.fillColor = category.categoryColor.cgColor
    shapeLayer.path = path.cgPath
    layer.addSublayer(shapeLayer)
}

@objc func touchDown(button: HexaButton, event: UIEvent) {
    if let touch = event.touches(for: button)?.first {
        let location = touch.location(in: button)

        if path.contains(location) == false {
            button.cancelTracking(with: nil)
        }
    }
}

public func roundedPolygonPath(rect: CGRect, lineWidth: CGFloat, sides: NSInteger, cornerRadius: CGFloat, rotationOffset: CGFloat = 0) -> UIBezierPath {
        let path = UIBezierPath()
        let theta: CGFloat = CGFloat(2.0 * .pi) / CGFloat(sides) // How much to turn at every corner
        let width = min(rect.size.width, rect.size.height)        // Width of the square
        
        let center = CGPoint(x: rect.origin.x + width / 2.0, y: rect.origin.y + width / 2.0)
        
        // Radius of the circle that encircles the polygon
        // Notice that the radius is adjusted for the corners, that way the largest outer
        // dimension of the resulting shape is always exactly the width - linewidth
        let radius = (width - lineWidth + cornerRadius - (cos(theta) * cornerRadius)) / 2.0
        
        // Start drawing at a point, which by default is at the right hand edge
        // but can be offset
        var angle = CGFloat(rotationOffset)
        
        let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle))
        path.move(to: CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta)))
        
        for _ in 0..<sides {
            angle += theta
            
            let corner = CGPoint(x: center.x + (radius - cornerRadius) * cos(angle), y: center.y + (radius - cornerRadius) * sin(angle))
            let tip = CGPoint(x: center.x + radius * cos(angle), y: center.y + radius * sin(angle))
            let start = CGPoint(x: corner.x + cornerRadius * cos(angle - theta), y: corner.y + cornerRadius * sin(angle - theta))
            let end = CGPoint(x: corner.x + cornerRadius * cos(angle + theta), y: corner.y + cornerRadius * sin(angle + theta))
            
            path.addLine(to: start)
            path.addQuadCurve(to: end, controlPoint: tip)
        }
        
        path.close()
        
        // Move the path to the correct origins
        let bounds = path.bounds
        let transform = CGAffineTransform(translationX: -bounds.origin.x + rect.origin.x + lineWidth / 2.0, y: -bounds.origin.y + rect.origin.y + lineWidth / 2.0)
        path.apply(transform)
        
        return path
    }
}

有人能给我指出正确的方向吗?我错过了什么?谢谢

【问题讨论】:

    标签: ios swift custom-button


    【解决方案1】:

    当你覆盖 draw -

    override func draw(_ rect: CGRect) {
    }
    

    你没有打电话给super.draw(rect),这意味着你不会得到UIButton的任何绘图。

    您可以删除您的 draw(_ rect: CGRect) 实现并将您的形状层代码移动到 layoutSubviews() 方法中。

    此外,您不应该在每次调用它时都添加一个新层。考虑以下之一 -

    1. 只添加一次形状层,每次调用时更新它的框架。

    2. 每次都添加新的形状层(在添加新实例之前删除旧实例)。

    这将为您返回 UIButton 的内置绘图。

    此外,当您添加一个图层时,您正在调用addSublayer,这会将您的子图层添加到按钮图层层次结构中的所有其他内容之上,完全覆盖由按钮的默认绘图呈现的所有内容。

    考虑使用 insertSublayer 变体 - at: indexbelow: sublayer 等。

    【讨论】:

    • 谢谢@Tarun,你是对的。参数“addSublayer”堆叠在顶部并使用“insertSublayer at:0”完成了这个技巧,同时按照您的建议将代码移动到“layoutSubviews()”!我将更多地研究如何将 CAShapeLayer 绘制到现有上下文中......非常感谢
    猜你喜欢
    • 2020-06-29
    • 2015-01-07
    • 2016-11-21
    • 1970-01-01
    • 2014-09-01
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多