DEV Community

Cover image for Understanding Styles in programmatic UI.
Aaron Cleveland
Aaron Cleveland

Posted on

Understanding Styles in programmatic UI.

Inspiration

When you look for inspiration whether it be from the great mind of yourself, or from sites like dribble. Like the example above, we can see multiple buttons and labels that could be reusable.

Creating programmatic stored properties with the same methods is tedious and unnecessary. If it doesn’t follow the DRY concept then refactor it.

  • D: Don’t
  • R: Repeat
  • Y: Yourself

When writing code, and we notice that these two stored properties share some common interest.

let articleTitle: UILabel = {
 let articleTitle = UILabel()
 articleTitle.translateAutoresizeMaskIntoConstraints = false
 articleTitle.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
 articleTitle.textColor = .white
 articleTitle.numberOfLines = 0
 return articleTitle
}()
Enter fullscreen mode Exit fullscreen mode
  • translatesAutoresizingMaskIntoConstraints = false
  • font = UIFont.systemFont()
  • textColor = .white

This is six lines of unwanted code, let's implement a style file that will assist with fixing this issue!


class TestUIStyle: UILabel {
 enum Style {
  /*
   I usually determine my cases based on the needs of the project. Let's try to get some of the details in order.
  */
  // HomeView
  case title, header
 }
}
Enter fullscreen mode Exit fullscreen mode

I created a new Swift file and named it TestUIStyle. The style that I want to mimic is for labels, I am gonna subclass it as a UILabel and start with an enum called "Style". As you can see I have determined from our dribble image that we have a ton of labels that are gonna follow suit.


let style: Style
init(style: Style, text: String) {
 self.style = style
 super.init(frame: .zero)
 self.text = text
 setupStyling()
}

required init?(coder: NSCoder) {
 fatalError("init(coder:) has not been implemented")
}

private func setupStyling() {

}
Enter fullscreen mode Exit fullscreen mode

Now we are gonna create a constant and set it to our enum and initialize it. This allows us to choose which style wants and the given text that you would like when creating it in our ViewControllers. The "text: String" is optional and it's not a requirement if you prefer not to.


private func setupStyling() {
 translatesAutoresizingMaskIntoConstraints = false
 numberOfLines = 0

 switch style {
  case .header:
   font = .systemFont(ofSize: 20, weight: .bold)
   textColor = .label
  case .title:
   font = .systemFont(ofSize: 14, weight: .light)
   textColor = .white
  default:
   font = .systemFont(ofSize: 12, weight: .regular)
   textcolor = .yellow
 }
}
Enter fullscreen mode Exit fullscreen mode

As you can see with each style that is being switched they have their own set attributes but they all conform to two things that we need from them all.

  • translatesAutoResizingMaskIntoConstraints = false
  • numberOfLines = 0

Let's see how this style file can go from what we had before to now!


// New code from the style
let articleTitle = TestUIStyle(style: .title, text: "Medium"
let articleHeader = TestUIStyle(style: .header, text: "Name of Source"

// Old code from the style
let articleTitle: UILabel = {
 let articleTitle = UILabel()
 articleTitle.translatesAutoresizingMaskIntoConstraints = false
 articleTitle.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
 articleTitle.textColor = .white
 articleTitle.numberOfLines = 0
 return articleTitle
}
Enter fullscreen mode Exit fullscreen mode

Cleaning up unwanted code could be a huge time saver when working with programmatic UI. We are able to bring everything down to two lines.

Alt Text

Here is the full sample code for viewing! Hope you’re just like me and prefer your things DRY!

import Foundation
import UIKit

class TestUIStyle: UILabel {
    enum Style {
        // HomeView
        case header, description, title, dates, author
        // ArticleDetailView
        case detailTitle, detailDate, detailAuthor, detailPaper, detailContent
        // CollectionView
        case collectionTitle, collectionAuthor
    }

    let style: Style
    init(style: Style, text: String) {
        self.style = style
        super.init(frame: .zero)
        self.text = text
        setupStyling()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupStyling() {
        translatesAutoresizingMaskIntoConstraints = false
        numberOfLines = 0

        switch style {
        case .header:
            font = .systemFont(ofSize: 20, weight: .bold)
            textColor = .label
        case .title:
            font = .systemFont(ofSize: 14, weight: .light)
            textColor = .white
        default:
            font = .systemFont(ofSize: 12, weight: .regular)
            textColor = .yellow
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)