Learn to design and construct reusable consumer interface parts by utilizing customized view subclasses from the UIKit framework in Swift.
UIKit
The issue: UI, UX, design
Constructing consumer 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 consumer interacts with the appliance, 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 consumer interfaces is probably the most difficult drawback in many of the circumstances. Frontend techniques these days (cellular, pill, even desktop apps) are simply fancy overlays on prime of some JSON knowledge from a service / API. 🤷♂️
Why is it so onerous? Effectively, I consider that if you wish to be a great designer, you want a correct engineering mindset as nicely. You must be able to observing the entire system (massive image), assemble constant UI parts (that truly look the identical in every single place), plan the desired expertise based mostly on the practical specification and lots of extra. It is also fairly a primary requirement to be an artist, assume exterior of the field, and have the ability to clarify (describe) your thought to others. 🤯
Now inform me whose job is the toughest within the tech business? Yep, as a free of charge everyone seems to be a designer these days, additionally some corporations do not rent this type of consultants in any respect, however merely let the work accomplished by the builders. Anyway, let’s deal with the right way to 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 prefer to set design properties like font
, textColor
, backgroundColor
instantly on the view cases. Though in some circumstances I discovered the looks proxy very good, however nonetheless somewhat buggy. Perhaps this can change with iOS 13 and the arrival of the lengthy awaited darkish mode.
Pricey Apple please make an auto swap based mostly on day / night time cycles (you understand just like the sundown, dawn possibility within the residence app). 🌙
- Fashion is a group of attributes that specifiy the looks for a single view.
- Theme is a set of comparable wanting view kinds, utilized to the entire software.
These days I normally create some predefined set of styling parts, more than likely fonts, colours, however generally icons, and so on. I prefer to go along with the next construction:
Fonts
- title
- heading
- subheading
- physique
- small
Colours
Icons
You possibly can have much more parts, 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 fashion I get a reasonably easy syntax, which is sweet, altough this would possibly 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 many of the circumstances it isn’t a requirement. 😅
Structs vs enums:
I might use enums as an alternative of structs with static properties, however on this case I just like the simplicity of this strategy. I do not need to fiddle with uncooked values or extensions that accepts enums. It is only a private choice.
What if it’s important to help a number of themes?
That is not an enormous challenge, you’ll be able to outline a protocol to your wants, and implement the required theme protocol as you need. The actual drawback is when it’s important to swap between your themes, as a result of it’s important to refresh / reload your whole UI. ♻️
There are some greatest practices, for instance you should utilize the NSNotificationCenter
class in an effort 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 appliance, so this implies you mainly begin from scratch with a model new rootViewController. 😱
Anyway, examine the hyperlinks beneath for those who want one thing like this, however for those who simply need to help darkish mode in your app, I might recommend to attend till the primary iOS 13 beta comes out. Perhaps Apple will give some shiny new API to make issues simple.
Customized views as fashion parts
I promised styling by subclassing, so let’s dive into the subject. Now that we now have a great answer to outline fonts, colours and different primary constructing blocks, it is time to apply these kinds to precise UI parts. After all you should utilize the UIAppearance API, however for instance you’ll be able to’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 count on that factor to observe the identical guideline in every single place else. I remedy this drawback by creating subclasses for each single view factor that has a customized fashion 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 in case you have subclasses and also you’re working with autolayout constraints from code, that you would be able to put all of your constraint creation logic instantly 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’ll be able to see I solely should 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 should set the category title in interface builder, or you’ll be able to 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 based mostly in your present scenario with further parameters, so it is fairly scalable for each scenario. 👍
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 must subclass each single view kind (button, label, and so on) and actually copy & paste your initialization strategies repeatedly. I have already got some articles about this, examine the hyperlinks beneath. 👇
To be able to remedy this drawback I normally find yourself by making a mother or father 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 further I simply should 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 a lot better, as a result of I haven’t got to take care of the required view initialization strategies anymore, additionally autoresizing will likely 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 practical programming) is nice for those who use it in the fitting place, however since UIKit is kind of an OOP framework I consider it is nonetheless higher to observe these paradigms as an alternative of selecting some hacky manner. 🤪
If you happen to like my publish, please additionally observe me on twitter, and subscribe to my month-to-month publication. It is 100% Swift solely content material, no spam ever!