The issue: UI, UX, design
Constructing person interfaces is the toughest a part of the job!
In a nutshell: design is a strategy of determining the very best answer that matches a particular downside. Graphic design often 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 let you know that determining and implementing correct person interfaces is probably the most difficult downside in a lot of the circumstances. Frontend programs these days (cell, pill, even desktop apps) are simply fancy overlays on prime of some JSON knowledge from a service / API. 🤷♂️
Why is it so exhausting? Nicely, I imagine that if you wish to be a superb designer, you want a correct engineering mindset as nicely. It’s important 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 primarily based on the purposeful specification and lots of extra. It is also fairly a primary requirement to be an artist, suppose exterior of the field, and be capable of clarify (describe) your thought 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 type of consultants in any respect, however merely let the work completed by the builders. Anyway, let’s deal with create good and reusable design implementations by utilizing subclasses in Swift. 👍
Look, themes and types
Let me begin with a confession: I barely use the UIAppearance API. This can be a private desire, however I prefer to set design properties like font, textColor, backgroundColor immediately on the view cases. Though in some circumstances I discovered the looks proxy very good, however nonetheless a bit buggy. Perhaps this can change with iOS 13 and the arrival of the lengthy awaited darkish mode.
Expensive Apple please make an auto swap primarily based on day / night time cycles (you recognize just like the sundown, dawn possibility within the house app). 🌙
- Fashion is a set of attributes that specify the looks for a single view.
- Theme is a set of comparable wanting view types, utilized to the entire software.
These days I often create some predefined set of styling components, most probably fonts, colours, however typically icons, and so on. I prefer to go together with the next construction:
Fonts
- title
- heading
- subheading
- physique
- small
Colours
Icons
You’ll be able to have much more components, however for the sake of simplicity let’s simply implement these ones with a very 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 fairly easy syntax, which is sweet, though this may not let me do dynamic styling, so I cannot swap between gentle / 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 strategy. I do not wish to fiddle with uncooked values or extensions that accepts enums. It is only a private desire.
What if you need to help a number of themes?
That is not a giant problem, you possibly can outline a protocol on your wants, and implement the required theme protocol as you need. The actual downside is when you need to swap between your themes, as a result of you need to refresh / reload your whole UI. ♻️
There are some finest practices, for instance you need to use the NSNotificationCenter class to be able 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, examine the hyperlinks beneath in case you want one thing like this, however in case you simply wish to help darkish mode in your app, I might 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 now we have a superb answer to outline fonts, colours and different primary constructing blocks, it is time to apply these types to precise UI components. In fact you need to use the UIAppearance API, however for instance you possibly can’t merely set customized fonts by way of 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 remedy this downside by creating subclasses for each single view component that has a customized type utilized to it. So for instance:
- TitleLabel (blue shade, 32pt system font)
- HeadingLabel (blue shade, 24pt system font)
- StandardButton (blue background)
- DestructiveButton (pink background)
One other good factor if in case you have subclasses and also you’re working with autolayout constraints from code, you could put all of your constraint creation logic immediately 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 possibly can see I solely need to set the font & textColor attributes as soon as, so after the view initialization is completed, I can make sure that each single occasion of TitleLabel will look precisely the identical. The utilization is fairly easy too, you simply need to set the category title in interface builder, or you possibly can merely create the view like this:
let titleLabel = TitleLabel()
self.view.addSubview(titleLabel)
NSLayoutConstraint.activate(titleLabel.constraints(in: self.view))
The factor I like probably the most about this strategy is that my constraints are going to be simply in the fitting place, so they will not bloat my view controller’s loadView methodology. You may as well create a number of constraint variations primarily based in your present scenario with further parameters, so it is fairly scalable for each scenario. 👍
View initialization is tough
The draw back of this answer is that view initialization is type of tousled, due to the interface builder help. It’s important to subclass each single view kind (button, label, and so on) and actually copy & paste your initialization strategies many times. I have already got some articles about this, examine the hyperlinks beneath. 👇
So as to remedy this downside I often find yourself by making a dad or mum 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 more I simply need to override the initialize methodology.
class TitleLabel: Label {
override func initialize() {
tremendous.initialize()
self.font = App.Fonts.title
self.textColor = App.Colours.title
}
}
See, it is so significantly better, as a result of I haven’t got to take care of the required view initialization strategies anymore, additionally auto-resizing might be off by default. ❤️
My ultimate takeaway from this lesson is that you simply shouldn’t be afraid of courses and object oriented programming if it involves the UIKit framework. Protocol oriented programming (additionally purposeful programming) is nice in case you use it in the fitting place, however since UIKit is sort of an OOP framework I imagine it is nonetheless higher to comply with these paradigms as a substitute of selecting some hacky manner. 🤪