Jupiter869
Jupiter869

Reputation: 657

Controlling Button Appearance Globally

I've been trying to control the appearance of all of my buttons in my project. I've created an Extension and put it at the top of one ViewController file to control the appearance of all of the buttons in that View. It works great. Here it is:

    import UIKit

    // EXTENSION TO CONTROL BUTTON APPEARANCE
    extension UIButton {
        func styleButton() {
            self.layer.cornerRadius = 8
            self.layer.borderWidth = 2
            self.layer.borderColor = UIColor.red.cgColor
        }
    }

    class DefaultSettingsVC: UIViewController, UITextFieldDelegate {
    ...
    // IN VIEWDIDLOAD :
         myButton1.styleButton()
         myButton2.styleButton()  //etc.

The only thing is I need to put it at the top of every ViewController file. (I hope I'm using the right terminology here.) So instead of that, I thought I would create an entirely new file which is a subclass of UIButton. This is the contents of the entire file:

import UIKit

class ButtonStyle: UIButton {
    func styleButton() {
        self.layer.cornerRadius = 8
        self.layer.borderWidth = 2
        self.layer.borderColor = UIColor.red.cgColor
    }
}

But now what?! When I try to add it to to the Class line in my ViewController files, I get a "Multiple inheritance from classes" error.

class DefaultSettingsVC: UIViewController, UITextFieldDelegate, ButtonStyle {

Am I completely on the wrong track here? Should I be doing this an entirely different way? Any help would be great. My Swift expertise is only a 2.5 out of 5 so I'm still learning and would appreciate some guidance if you can.

Upvotes: 0

Views: 858

Answers (2)

Ahmad F
Ahmad F

Reputation: 31685

I would suggest to apply the desired style for all buttons in all ViewControllers by:

  • Create a custom UIViewController super class for all of the ViewControllers in your application.

  • Let the super class handles the applying of the desired style for all buttons in its view.

The super class should be similar to:

class BaseViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        setupButtonsStyle()
    }

    func setupButtonsStyle() {
        for subview in view.allSubViews.filter({$0 is UIButton}) {
            let button = subview as! UIButton
            button.layer.cornerRadius = 8
            button.layer.borderWidth = 2
            button.layer.borderColor = UIColor.red.cgColor
        }
    }
}

extension UIView {
    var allSubViews : [UIView] {
        var array = [self.subviews].flatMap {$0}
        array.forEach { array.append(contentsOf: $0.allSubViews) }

        return array
    }
}

Note the the purpose of declaring allSubViews is to get all views and their subviews in a view.

Make sure that the sub class(es) viewDidLoad() method contains super.viewDidLoad():

class ViewController: BaseViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

This approach saves the time of calling the style method for each single button in your application (you don't have to call button.styleButton manually for each button), all you have to do is to let the desired ViewController to be as a subclass of the super class.

Hope this helped.

Upvotes: 0

raphh
raphh

Reputation: 618

You shouldn't use sublassing to do this. Extensions are the way to go! If you want to be able to use the extension in different classes, you should try to put it in a separated file. Since you're extending the UIButton class, you want it to be accessible from everywhere.

See, the ViewController class :

class MyViewController: UIViewController {

    var button = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        button.styleButton(cornerRadius: 8, borderWidth: 2, borderColor: UIColor.red.cgColor)
    }
}

And your extension file :

extension UIButton {
    func styleButton(cornerRadius: CGFloat, borderWidth: CGFloat, borderColor: CGColor) {
        self.layer.cornerRadius = cornerRadius
        self.layer.borderWidth = borderWidth
        self.layer.borderColor = borderColor
    }
}

I tweaked it a little bit so now you're able to set the parameters you want in case you need later to style some buttons differently. It is more reusable in my opinion so more useful.

Upvotes: 2

Related Questions