1

I've looked at almost every stackoverflow solution and for some odd reason my button will not round the corners. Can someone check and see what im doing wrong?

let goToMapsButton = UIButton(type: .custom)
    scrollView.addSubview(goToMapsButton)
       _ = goToMapsButton.anchor(map.bottomAnchor, left: nil, bottom: seperator.topAnchor, right: self.view.rightAnchor, topConstant: 16, leftConstant: 0, bottomConstant: 16, rightConstant: 16, widthConstant: 50, heightConstant: 50)


    goToMapsButton.backgroundColor = .green
    goToMapsButton.layer.cornerRadius = 0.5 * goToMapsButton.bounds.size.width
    goToMapsButton.clipsToBounds = true
    goToMapsButton.layer.masksToBounds = true

Btw, Im doing this all in the viewDidLoad section of the view controller, if that info makes a difference.

Here is the full viewDidLoadClass for reference:` override func viewDidLoad() { super.viewDidLoad()

    let map = MKMapView()
    let view1 = UIView()
    view1.backgroundColor = .red

    let storeAddress = UILabel()
    storeAddress.text = "318 Atwood Avenue"
    storeAddress.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.medium)

    let storeCity = UILabel()
    storeCity.text = "Rainy River"
    storeCity.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.medium)

    let seperator = UIView()
    seperator.backgroundColor = .lightGray

    let goToMapsButton = UIButton(type: .custom)


    scrollView.addSubview(map)
    scrollView.addSubview(view1)
    scrollView.addSubview(storeAddress)
    scrollView.addSubview(storeCity)
    scrollView.addSubview(goToMapsButton)
    scrollView.addSubview(seperator)

    map.anchorToTop(scrollView.topAnchor, left: self.view.leftAnchor, bottom: nil, right: self.view.rightAnchor)
    map.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.6).isActive = true

    _ = storeAddress.anchor(map.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: nil, topConstant: 16, leftConstant: 16, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
    _ = storeCity.anchor(storeAddress.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: nil, topConstant: 8, leftConstant: 16, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)

    _ = goToMapsButton.anchor(map.bottomAnchor, left: nil, bottom: nil, right: self.view.rightAnchor, topConstant: 16, leftConstant: 0, bottomConstant: 16, rightConstant: 16, widthConstant: 50, heightConstant: 50)
    goToMapsButton.backgroundColor = .green
    print(goToMapsButton.frame.width)
    goToMapsButton.layer.cornerRadius = 0.25 * goToMapsButton.frame.width
    goToMapsButton.clipsToBounds = true
    goToMapsButton.layer.masksToBounds = true


    _ = seperator.anchor(storeCity.bottomAnchor, left: self.view.leftAnchor, bottom: nil, right: self.view.rightAnchor, topConstant: 8, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 1)

    view1.anchorToTop(map.bottomAnchor, left: self.view.leftAnchor, bottom: scrollView.bottomAnchor, right: self.view.rightAnchor)
    view1.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.8).isActive = true

}`
  • 4
    `goToMapsButton.bounds.size.width` is zero. – rmaddy Feb 10 '18 at 04:01
  • Ah I see that, any suggestions for a solution then? – soulessfighter Feb 10 '18 at 04:15
  • 1
    Yes, try using `viewWillLayoutSubviews` first, but if it's still zero, use `viewDidLayoutSubviews`. You can set constraints - as long as they are *computing* frame-based `CGRect` values in `viewDidLoad`, but most times anything else needs to be later in the view lifecycle. –  Feb 10 '18 at 04:38
  • Here's the absolute best link I've ever found that explains what you need to learn: https://stackoverflow.com/questions/5562938/looking-to-understand-the-ios-uiviewcontroller-lifecycle#12608364 –  Feb 10 '18 at 04:40
  • I've tried that already to, does not work Any other suggestions? – soulessfighter Feb 10 '18 at 04:47

4 Answers4

6

Move this code in viewWillLayoutSubviews:

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    goToMapsButton.layer.cornerRadius = 0.25 * goToMapsButton.frame.width
}

Or create your custom class for button with rounded corners:

class RoundedButton: UIButton {
    @IBInspectable var cornerRadius: CGFloat = 0

    override func layoutSubviews() {
        super.layoutSubviews()
        clipsToBounds = true
        layer.cornerRadius = cornerRadius
    }
}
Ilya Kharabet
  • 4,203
  • 3
  • 15
  • 29
  • I was struggling to get a button within a collection view to round and this custom class approach did the trick for me. Thanks! – Steve B Jul 29 '20 at 21:22
1

I face the same issue today, I'm using Anchor too. Well it looks like a one line stuff to me, never think it would takes that much of code.

The difficult is that we cannot get the frame.height or width in UIButton property closure because autolayout has not calculate the size at that time. I do a test to apply the purely round corner in viewDidLayoutSubviews.

And this is what it is looks like, although the declaration is separated for those UIButtons. I really don't like this way, I want to put all button declaration code in the same place, like a closure. However I don't find any other way to do it in internet.

    let b1 = UIButton()
    let b2 = UIButton()
    let b3 = UIButton()
    let b4 = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()

        configureLayout()
    }

    private func configureLayout() {
        // disable large title
        navigationItem.largeTitleDisplayMode = .never
        
        let topLabel = UILabel()
        topLabel.text = "Import your music"
        topLabel.font = .systemFont(ofSize: 30, weight: .heavy)
        topLabel.numberOfLines = 0
        topLabel.textColor = .black
        topLabel.textAlignment = .center
        
        let stack = UIStackView()
        stack.translatesAutoresizingMaskIntoConstraints = false
        stack.axis = .vertical
        stack.spacing = 40
        stack.addArrangedSubview(topLabel)
        
        b1.setTitle("Local drive", for: .normal)
        b2.setTitle("Google", for: .normal)
        b3.setTitle("OneNote", for: .normal)
        b4.setTitle("DropBox", for: .normal)
        
        b1.backgroundColor = .myBlue
        b2.backgroundColor = .myGreen
        b3.backgroundColor = .systemPink
        b4.backgroundColor = .myPuple
        
        b1.tag = 1
        b2.tag = 2
        b3.tag = 3
        b4.tag = 4
        
        [b1, b2, b3, b4].forEach { b in
            b.titleLabel?.font = .systemFont(ofSize: 20, weight: .bold)
            b.setTitleColor(.white, for: .normal)
            b.setTitleColor(.gray, for: .highlighted)
            stack.addArrangedSubview(b)
            b.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        }
        view.addSubview(stack)
        
        let g = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            stack.centerXAnchor.constraint(equalTo: g.centerXAnchor),
            stack.centerYAnchor.constraint(equalTo: g.centerYAnchor),
            stack.widthAnchor.constraint(equalTo: g.widthAnchor, multiplier: 0.75)
        ])
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        [b1, b2, b3, b4].forEach { b in
            b.layer.cornerRadius = b1.frame.height / 2
            b.layer.cornerCurve = .continuous
        }
    }

enter image description here

Zhou Haibo
  • 1,681
  • 1
  • 12
  • 32
0

Give your button a frame. like that

goToMapsButton.frame = CGRect(x: xposition, y:yposition, width: widthyouwant, height: heightyouwant)

as currently your size of button is zero 0*0.5 = zero thats why its not applying any radius. give it frame and it will work...

junaid
  • 193
  • 1
  • 16
0

UIButton might have a background UIImage with rounded corners. It allowes you to set a background UIImage for each UIControlState of your UIButton.

open class UIButton : UIControl, NSCoding {

    open func setBackgroundImage(_ image: UIImage?, for state: UIControlState)
}

If your UIButton's size is determined at runtime and the radius is fixed - you can use a resizable image:

open class UIImage : NSObject, NSSecureCoding {

    open func resizableImage(withCapInsets capInsets: UIEdgeInsets) -> UIImage
}

On the gif below I use UIImage with size = CGSize(width: 7, height: 7), corner radius = 3 and cap insets = UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3)

enter image description here

iWheelBuy
  • 5,470
  • 2
  • 37
  • 71