Setting style for UIComponents - swift

Is it possible to make one style for UIButton (or any UI component) and set that style for selected buttons from Xcode Interface (storyboard)?
Like in web-development you create one css class and use in any elements.

Yes, this possible. You need to make a custom button class, which is a subclass of
UIButton. For example, the code below sets the background color
class CustomButton: UIButton {
override func awakeFromNib() {
super.awakeFromNib()
setUpView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setUpView()
}
func setUpView() {
self.layer.cornerRadius = self.frame.width/2
self.layer.masksToBounds = true
self.backgroundColor = UIColor.red
}
}
Then in Xcode Interface (storyboard), for every button, you wish to use this style.
Set the Custom Class in the identity inspector.

It is possible to style all components of the same type by using UIAppearance. When it comes to styling individual components it's best to declare some common styling functions and then apply them on specific components. You could also create subclasses and style them individually.

Related

Set Accessibility Identifier in UIView Extension

I worked on Mobile Test Automation.Previous, some elements don't have any identifier but i need to import identifiers for testing issues.
So I decide to write an extension to UIView, hereby that code will be affect all codes so I wont need to add one by one.
How can I do ? Should I write on init or awakeFromNib ?
Thanks in advance.
Generally you'll want to have specific accessibility identifiers for elements you want to expose to the accessibility system.
You can set those directly in Storyboards/Interface Builder, or you can set them in your view's initializer when implementing UIs programatically:
class MyView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.accessibilityIdentifier = "my-custom-view"
let label = UILabel()
label.accessibilityIdentifier = "my-custom-label"
self.addSubview(label)
}
}

Any way to opt out of autoresizing permanently?

I'm writing nib-less views in which I use autolayout for all my layout logic. I find myself having to turn off autoresizing with every view I instantiate. My code is littered with a lot of these:
view.translatesAutoresizingMaskIntoConstraints
Ideally I'd like to just
extension UIView/NSView {
override var translatesAutoresizingMaskIntoConstraints: Bool = false
}
and get it over with once and for all, but extensions can't override stored properties.
Is there some other simple way to switch off autoresizing for good?
Well just a suggestion since its annoying to always set that to false, just setup a function with all the shared setups for the UIView and call it every time,
its saves time and its kinda less annoying than trying and setting the values each time,
extension UIView {
func notTranslated() {
self.translatesAutoresizingMaskIntoConstraints = false
//Add any additional code.
}
}
//Usage
let view = UIView()
view.notTranslated()
You can't override this constraints properties because the UIView maybe declared in the IB
translatesAutoresizingMaskIntoConstraints according to apple.
By default, the property is set to true for any view you programmatically create. If you add views in Interface Builder, the system automatically sets this property to false.
imagine if you could override that from an extension that would lead to some conflicts if there was other UIView's that's have the opposite value True || false, so in my opinion:
Apple did this to prevent any conflicts with the views constrains, therefore if you don't like to write it every time just wrap it up in a function.
Please if anyone have additional information, don't hesitate to contribute.
UPDATE: I found this cool answer that could also work, check out the code below.
class MyNibless: UIView {
//-----------------------------------------------------------------------------------------------------
//Constructors, Initializers, and UIView lifecycle
//-----------------------------------------------------------------------------------------------------
override init(frame: CGRect) {
super.init(frame: frame)
didLoad()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
didLoad()
}
convenience init() {
self.init(frame: CGRect.zero)
}
func didLoad() {
//Place your initialization code here
//I actually create & place constraints in here, instead of in
//updateConstraints
}
override func layoutSubviews() {
super.layoutSubviews()
//Custom manually positioning layout goes here (auto-layout pass has already run first pass)
}
override func updateConstraints() {
super.updateConstraints()
//Disable this if you are adding constraints manually
//or you're going to have a 'bad time'
//self.translatesAutoresizingMaskIntoConstraints = false
translatesAutoresizingMaskIntoConstraints = false
//Add custom constraint code here
}
}
var nibless: UIView = MyNibless()
//Usage
nibless.updateConstraints()
print(nibless.translatesAutoresizingMaskIntoConstraints) //false
So simply just create MyNibless instance as UIView and this also open big door to customizations too

UIAppearance overwrites custom textColor on UILabel

I setup UILabel appearance in my app delegate using:
UILabel.appearance().textColor = UIColor.white
I also have a custom UIView subclass that contains a UILabel along with some other elements (omitted here):
#IBDesignable
class CustomView: UIView {
private let descriptionLabel = HCLabel()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
private func setup() {
self.descriptionLabel.textColor = UIColor.black
// ... other things not related to descriptionLabel
}
}
If I instantiate CustomView in a storyboard, everything works just fine. If, however, I instantiate it in code, the descriptionLabel is white (appearance color), not black (the color I set). What's going on here? The way I understood it was that if I set a custom color, the appearance color will not be used.
What you're experiencing is simply a matter of the exact timing with which the UIAppearance proxy applies its settings to a new UIView. When are we to suppose it does this? It can't possibly do it before init, because init is the first thing that happens in the life of the UIView. Thus, the order of events is like this:
override init(frame: CGRect) {
super.init(frame: frame)
setup() // black
}
// and some time later, UIAppearance proxy comes along and sets it to white
So your goal is to call setup pretty early in the life of the label — and certainly before the user ever has a chance to see it — but not so early that the UIAppearance proxy acts later. Let's move the call to setup to a bit later in the life of the label:
// some time earlier, UIAppearance proxy sets it to white
override func didMoveToSuperview() {
setup() // black
}
Now we're acting after the appearance proxy has had a chance to act, and so your settings are the last to operate, and they win the day.
We remain in ignorance of how early we could move the call to setup and still come along after the appearance proxy setting has been obeyed. If you have time, you might like to experiment with that. For example, willMoveToSuperview is earlier; if you call setup there (and not in didMoveToSuperview), does that work? Play around and find out!

How to create a global function that affects all or specific UIButton instance types?

I want to create a global function that affects either all UIButton instances or only those of a certain UIButton type which would update the corner radius or border property. I'm familiar with UIAppearances however my client would like to have a global file where they could update changes on the fly as if it were a CSS stylesheet. So far I've been able to make extensions of UIColor and UIFont which returns specific colors and fonts however I can't figure out how this would work for UIButton instances. Here is what I've thought of so far however I don't think this would work:
#objc extension UIButton {
func changeUIButtonBorder() -> UIButton {
self.layer.borderWidth = 3
self.layer.borderColor = UIColor.white.cgColor
return self
}
}
What you're doing is great, and it does work for UIButton instances. But there is no need to return anything. In the extension, self is the button. So it can just change itself.
#objc extension UIButton {
func changeUIButtonBorder() {
self.layer.borderWidth = 3
self.layer.borderColor = UIColor.white.cgColor
}
}
You can now call changeUIButtonBorder on any UIButton instance.
#IBOutlet var myButton : UIButton!
override func viewDidLoad() {
super.viewDidLoad()
myButton.changeUIButtonBorder()
}
However, there is no magical way to shoutcast to all UIButtons that they should call that method; you'll have to deal with them one at a time.
The "magical" way is, as #Sh_Khan suggests, to make a UIButton subclass that calls changeUIButtonBorder in its own initializer. You would then simply have to make sure that all your buttons are instances of that subclass.
For example, here's a UIButton subclass that's always red (assuming that all instances come from the storyboard):
class RedButton : UIButton {
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = .red
}
}

How can I change the color of the UITableView for the entire application?

How can I change the color of the UITableView for the entire application?
Currently I have this set in some of my controllers but it does not work for some parts of the tableview.
self.tableView.backgroundColor = UIColor(red:0.20, green:0.22, blue:0.29, alpha:1.0)
UIAppearance does not support to change the background color of tableview in globally, you need to create the extension that inherits from UITableView, here is a link to an answer containing a list of all methods supported by UIAppearance.
for e.g
extension UITableView {
func setBGforTable(){
let divideCount: CGFloat = 255.0
self.backgroundColor = UIColor(red:0.20/divideCount, green:0.22/divideCount, blue:0.29/divideCount, alpha:1.0)
}
}
and call the method in your VC as
override func viewDidLoad() {
super.viewDidLoad()
yourtableViewName.setBGforTable()
}