简体   繁体   中英

Trouble with Rounded corner buttons being cut off

I have a custom button class I use to get rounded corners. The class works for some hard coded lengths/widths, but doesn't work for others. I have not been able to get it to work at all with dynamically sized buttons. As you can see by the picture, the button is cut off in various ways. Any idea what I'm doing wrong?

class CustomButton: UIButton{
    
     
       override init(frame: CGRect) {
           super.init(frame: frame)
           setupButton()
       }
       
       
       required init?(coder aDecoder: NSCoder) {
           super.init(coder: aDecoder)
           setupButton()
       }
       
       
       func setupButton() {
           setTitleColor(.white, for: .normal)
           layer.cornerRadius   = frame.size.height/2
           layer.masksToBounds = true
       }
       
}

在此处输入图片说明

Thanks for any help.

This happens because you set the corners just after button's creation using initial frame. Button's frame are changing during layout, but its corners are not redrawn. Just add setupButton call to layoutSubviews:

override func layoutSubviews() {
    super.layoutSubviews()
    setupButton()
}

Also I recommend you to use UIBezierPath approach instead of cornerRadius due to possible performance issues.

Although you are didn't share the issue code, Seems like you have issues with the layer! CALayer is Not auto-resizing due to frame changes, so it sets by the initial setup and stays the same. So first try to make it more like a view. The following code gives you a customizable gradient view that is reacting to any layout call (even right in the Storyboard!):

@IBDesignable
final class GradientView: UIView {

    @IBInspectable var firstColor: UIColor = .clear { didSet { updateView() } }
    @IBInspectable var secondColor: UIColor = .clear { didSet { updateView() } }

    @IBInspectable var startPoint: CGPoint = CGPoint(x: 0, y: 0) { didSet { updateView() } }
    @IBInspectable var endPoint: CGPoint = CGPoint(x: 1, y: 1) { didSet { updateView() } }

    override class var layerClass: AnyClass { get { CAGradientLayer.self } }

    override func layoutSubviews() {
        super.layoutSubviews()
        updateView()
        layer.frame = bounds
    }

    private func updateView() {
        let layer = self.layer as! CAGradientLayer
        layer.colors = [firstColor, secondColor].map {$0.cgColor}
        layer.startPoint = startPoint
        layer.endPoint = endPoint
    }
}

预览

Then you can add it to your custom view and frame it to the parent (or any other layout method that you like):

class CustomButton: UIButton{

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupButton()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupButton()
    }

    private lazy var gradientView: GradientView = {
        // Setup the gradient here
        let gradient = GradientView(frame: frame)
        gradient.startPoint = .init(x: 0, y: 0)
        gradient.endPoint = .init(x: 1, y: 1)
        gradient.firstColor = .red
        gradient.secondColor = .orange
        return gradient
    }()

    private func addLayerIfNeeded() {
        guard gradientView.superview == nil else { return }
        addSubview(gradientView)
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        gradientView.frame =  bounds
    }

    func setupButton() {
        addLayerIfNeeded()
        setTitleColor(.white, for: .normal)
    }
}

预览

I was able to fix the issue by applying the solutions in the article to my buttons as opposed to a view. This enabled dynamic resizing with gradients.

Why gradient doesn't cover the whole width of the view

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM