The issue: UI, UX, design
Constructing person interfaces is the toughest a part of the job!
In a nutshell: design is a means of determining the most effective answer that matches a particular drawback. Graphic design normally means the bodily drawing on a canvas or a paper. UX is actually how the person interacts with the applying, in different phrases: the general digital expertise of the “buyer” journey. UI is the seen interface that he/she’s going to see and work together with by touching the display screen. 👆
If I’ve to placed on the designer hat (and even the developer hat) I’ve to inform you that determining and implementing correct person interfaces is essentially the most difficult drawback in a lot of the circumstances. Frontend programs these days (cell, pill, even desktop apps) are simply fancy overlays on high of some JSON information from a service / API. 🤷♂️
Why is it so onerous? Nicely, I consider that if you wish to be an excellent designer, you want a correct engineering mindset as effectively. You need to be able to observing the entire system (large image), assemble constant UI components (that truly look the identical in all places), plan the specified expertise based mostly on the purposeful specification and lots of extra. It is also fairly a fundamental requirement to be an artist, suppose exterior of the field, and be capable of clarify (describe) your concept to others. 🤯
Now inform me whose job is the toughest within the tech trade? Yep, as a free of charge everyone seems to be a designer these days, additionally some firms do not rent this sort of specialists in any respect, however merely let the work carried out by the builders. Anyway, let’s give attention to how you can create good and reusable design implementations by utilizing subclasses in Swift. 👍
Look, themes and kinds
Let me begin with a confession: I barely use the UIAppearance API. This can be a private choice, however I wish to set design properties like font, textColor, backgroundColor straight on the view situations. Though in some circumstances I discovered the looks proxy very good, however nonetheless a bit of buggy. Perhaps this can change with iOS 13 and the arrival of the lengthy awaited darkish mode.
Expensive Apple please make an auto swap based mostly on day / night time cycles (you recognize just like the sundown, dawn choice within the house app). 🌙
- Model is a set of attributes that specify the looks for a single view.
- Theme is a set of comparable trying view kinds, utilized to the entire software.
These days I normally create some predefined set of styling components, most definitely fonts, colours, however typically icons, and so forth. I wish to go together with the next construction:
Fonts
- title
- heading
- subheading
- physique
- small
Colours
Icons
You may have much more components, however for the sake of simplicity let’s simply implement these ones with a extremely easy Swift answer utilizing nested structs:
struct App {
struct Fonts {
static let title = UIFont.systemFont(ofSize: 32)
static let heading = UIFont.systemFont(ofSize: 24)
static let subheading = UIFont.systemFont(ofSize: 20)
static let physique = UIFont.systemFont(ofSize: 16)
static let small = UIFont.systemFont(ofSize: 14)
}
struct Colours {
static let title = UIColor.blue
static let heading = UIColor.black
static let background = UIColor.white
}
struct Icons {
static let again = UIImage(named: "BackIcon")!
static let share = UIImage(named: "ShareIcon")!
}
}
App.Fonts.title
App.Colours.background
App.Icons.again
This manner I get a reasonably easy syntax, which is good, though this may not let me do dynamic styling, so I can’t swap between mild / darkish theme, however I actually do not thoughts that, as a result of in a lot of the circumstances it is not a requirement. 😅
Structs vs enums:
I might use enums as a substitute of structs with static properties, however on this case I just like the simplicity of this method. I do not wish to fiddle with uncooked values or extensions that accepts enums. It is only a private choice.
What if you need to help a number of themes?
That is not an enormous problem, you may outline a protocol on your wants, and implement the required theme protocol as you need. The true drawback is when you need to swap between your themes, as a result of you need to refresh / reload your whole UI. ♻️
There are some greatest practices, for instance you need to use the NSNotificationCenter class with the intention to notify each view / controller in your app to refresh if a theme change happens. One other answer is to easily reinitialize the entire UI of the applying, so this implies you mainly begin from scratch with a model new rootViewController. 😱
Anyway, test the hyperlinks under if you happen to want one thing like this, however if you happen to simply wish to help darkish mode in your app, I would counsel to attend till the primary iOS 13 beta comes out. Perhaps Apple will give some shiny new API to make issues straightforward.
Customized views as type components
I promised styling by subclassing, so let’s dive into the subject. Now that we now have an excellent answer to outline fonts, colours and different fundamental constructing blocks, it is time to apply these kinds to precise UI components. After all you need to use the UIAppearance API, however for instance you may’t merely set customized fonts by the looks proxy. 😢
One other factor is that I like consistency in design. So if a title is a blue, 32pt daring system font someplace in my software I additionally anticipate that component to comply with the identical guideline in all places else. I resolve this drawback by creating subclasses for each single view component that has a customized type utilized to it. So for instance:
- TitleLabel (blue coloration, 32pt system font)
- HeadingLabel (blue coloration, 24pt system font)
- StandardButton (blue background)
- DestructiveButton (purple background)
One other good factor you probably have subclasses and also you’re working with autolayout constraints from code, you could put all of your constraint creation logic straight into the subclass itself. Let me present you an instance:
import UIKit
class TitleLabel: UILabel {
override init(body: CGRect) {
tremendous.init(body: body)
self.initialize()
}
required init?(coder aDecoder: NSCoder) {
tremendous.init(coder: aDecoder)
self.initialize()
}
init() {
tremendous.init(body: .zero)
self.initialize()
}
func initialize() {
self.translatesAutoresizingMaskIntoConstraints = false
self.textColor = App.Colours.title
self.font = App.Fonts.title
}
func constraints(in view: UIView) -> [NSLayoutConstraint] {
return [
self.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
self.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
self.centerYAnchor.constraint(equalTo: view.centerYAnchor),
]
}
}
As you may see I solely need to set the font & textColor attributes as soon as, so after the view initialization is finished, I can ensure that each single occasion of TitleLabel will look precisely the identical. The utilization is fairly easy too, you simply need to set the category identify in interface builder, or you may merely create the view like this:
let titleLabel = TitleLabel()
self.view.addSubview(titleLabel)
NSLayoutConstraint.activate(titleLabel.constraints(in: self.view))
The factor I like essentially the most about this method is that my constraints are going to be simply in the correct place, so they will not bloat my view controller’s loadView technique. You may as well create a number of constraint variations based mostly in your present state of affairs with further parameters, so it is fairly scalable for each state of affairs. 👍
View initialization is difficult
The draw back of this answer is that view initialization is sort of tousled, due to the interface builder help. You need to subclass each single view kind (button, label, and so forth) and actually copy & paste your initialization strategies many times. I have already got some articles about this, test the hyperlinks under. 👇
So as to resolve this drawback I normally find yourself by making a guardian class for my very own styled views. Right here is an instance for an summary base class for my labels:
class Label: UILabel {
override init(body: CGRect) {
tremendous.init(body: body)
self.initialize()
}
required init?(coder aDecoder: NSCoder) {
tremendous.init(coder: aDecoder)
self.initialize()
}
init() {
tremendous.init(body: .zero)
self.initialize()
}
func initialize() {
self.translatesAutoresizingMaskIntoConstraints = false
}
}
So any longer I simply need to override the initialize technique.
class TitleLabel: Label {
override func initialize() {
tremendous.initialize()
self.font = App.Fonts.title
self.textColor = App.Colours.title
}
}
See, it is so a lot better, as a result of I haven’t got to take care of the required view initialization strategies anymore, additionally auto-resizing will likely be off by default. ❤️
My remaining takeaway from this lesson is that you just shouldn’t be afraid of lessons and object oriented programming if it involves the UIKit framework. Protocol oriented programming (additionally purposeful programming) is nice if you happen to use it in the correct place, however since UIKit is sort of an OOP framework I consider it is nonetheless higher to comply with these paradigms as a substitute of selecting some hacky means. 🤪
