1
votes

I have created a custom UIButton to use programmatically in my app. On one screen it works fine. On another, the background does not show up. I have looked up many similar questions and also compared the code to the other View Controller it's used in when it works and there are no obvious reasons. Why is the background color not showing?

The Custom Button Class

import Foundation
import UIKit

class PillButton: UIButton {

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

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

private func initializeButton() {
    backgroundColor = UIColor.white
    setTitleColor(UIColor(named: "pink"), for: .normal)
    contentEdgeInsets = UIEdgeInsets.init(top: 16, left: 48, bottom: 16, right: 48)
    translatesAutoresizingMaskIntoConstraints = false
}

override func layoutSubviews() {
    super.layoutSubviews()
    let height = frame.height / 2
    layer.cornerRadius = height
}
}

The View Controller

import Foundation
import UIKit
import MaterialComponents

class EventViewController: BaseViewController {

    private static let HORIZONTAL_PADDING: CGFloat = 16

    private var confirmButton: PillButton!
    private var unableToAttendButton: UILabel!
    private var signedUpLabel: UILabel!
    private var baseScrollView: UIScrollView!
    var event: Event!
    private var viewModel: EventViewModel = EventViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        createView()
    }

    override func createView() {
        super.createView()
        createConfirmButton()
    }


    private func createConfirmButton() {
        confirmButton = PillButton()

        let descriptionBottomGuide = UILayoutGuide()

        baseScrollView.addSubview(confirmButton)
        baseScrollView.addLayoutGuide(descriptionBottomGuide)

        descriptionBottomGuide.topAnchor.constraint(equalTo: eventDescription.bottomAnchor).isActive = true

        confirmButton.centerXAnchor.constraint(equalTo: baseScrollView.centerXAnchor).isActive = true
        confirmButton.topAnchor.constraint(equalTo: descriptionBottomGuide.bottomAnchor, constant: 20).isActive = true
    }

}

result

2
Button code looks fine, but the ViewController's logic isn't fully reproducible - may be you should provide code for creating baseScrollView and a screenshot of your resulting layout (with wrong button color)Mikhail Vasilev

2 Answers

0
votes
confirmButton = PillButton()

I would look into this piece of code. The designated initializers, the ones with frame and coder, in the custom button class call initializeButton(), but you are not implementing init() to do the same.

I would change it to confirmButton = PillButton(frame:)

0
votes

The code you posted has a LOT of information that you didn't provide, so it's pretty difficult to know what might be going on.

That said, you have a few issues with your PillButton class:

  • you should not be calling initializeButton in layoutSubviews()
  • you should update the corner radius in layoutSubviews()
  • no need to override setTitle
  • no need to set the layer background color, and you've already set the button's background color so no need to set it again.

Also, in the code you posted, you're not setting the button title anywhere.

Try replacing your PillButton class with this one, and see if you get better results:

class PillButton: UIButton {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initializeButton()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        initializeButton()
    }
    
    private func initializeButton() {
        backgroundColor = Colors.black
        setTitleColor(UIColor(named: "pink"), for: .normal)
        contentEdgeInsets = UIEdgeInsets.init(top: 16, left: 48, bottom: 16, right: 48)
        translatesAutoresizingMaskIntoConstraints = false
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        // update corner radius here!
        layer.cornerRadius = bounds.height / 2
    }
    
}

If you don't, then you need to do some debugging through the rest of your code (that you have not posted here) to find out what's going on.