Skip to content

Latest commit

 

History

History
320 lines (213 loc) · 7.27 KB

File metadata and controls

320 lines (213 loc) · 7.27 KB

Creating Custom Views

Agenda

  • Review Onboarding assignment
  • Creating custom views
  • xib files

Learning Objectives

By the end of this lesson, students should be able to:

  • Create custom views programmatically
  • Implement custom views using xib files

Onboarding assignment

  • 👯 Get in pairs or groups of 3.
  • 🕵🏻 Review each other's code.
  • 🙌🏼 See if you can get unblocked with tips from your classmates.
  • 📝 Keep a list of the things you are still missing or would like to change after reviewing your code in groups.

🤔

Have you noticed that our current solution for the Onboarding has too much going on in the same file?

Facts:

  • It works
  • It takes time to find where things are
  • Can definitely be improved

How?

Creating Custom Views

Creating custom views will help with:

  • Making code reusable.
  • Making code more readable.
  • Sometimes reduce the amount of code.
  • Separation of concerns.
  • Help with the file structure in the project.

We can create them 2 ways:

  • programmatically
  • xib files

Programmatically

We need a new file to get started.

File → New → File → Cocoa Touch Class

Name: MyCustomView
Subclass of UIView

class MyCustomView: UIView{


}
This is the empty class we get.
class MyCustomView: UIView{
    override init(frame: CGRect){
        super.init(frame: frame)
    }
}
We add custom functionality to the view by overriding the init method and still call it in the base class to set the frame.
class MyCustomView: UIView{
    override init(frame: CGRect){
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder){
        super.init(coder: aDecoder)
    }
}
Xcode will ask for this other required init. Which is needed in all subclasses of UIView
class MyCustomView: UIView{
    override init(frame: CGRect){
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder){
        super.init(coder: aDecoder)
        setup()
    }

    private func setup(){
        self.backgroundColor = UIColor.purple
        self.translatesAutoresizingMaskIntoConstraints = false
    }
}
Any custom behavior can live in a separate method and make sure to call it in the initializers if applicable.
class ViewController: UIViewController {

    let topView: MyCustomView = {
        let view = MyCustomView()
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(topView)
        NSLayoutConstraint.activate([
        topView.widthAnchor.constraint(equalToConstant: 100),
        topView.heightAnchor.constraint(equalToConstant: 100),
        topView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        topView.centerYAnchor.constraint(equalTo: view.centerYAnchor)])
    }
}

The true value of reusing

We now have a custom class for a view that's purple. We can create as many as we want in our project.

That's useful, but we are not exploiting the most out of our custom class.

What if I want to make squares of different colors?

Custom initializer

class MyCustomView: UIView {
    var color: UIColor? = .purple

    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    convenience init(color:UIColor){
        self.init(frame: .zero)
        self.color = color
        setup()
    }

    private func setup(){
        self.translatesAutoresizingMaskIntoConstraints = false
        self.backgroundColor = color
    }
}

Usage

class ViewController: UIViewController {

    let topView: MyCustomView = {
        let view = MyCustomView(color: .systemPink)
        return view
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(topView)
        NSLayoutConstraint.activate([
        topView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        topView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        topView.widthAnchor.constraint(equalToConstant: 100),
        topView.heightAnchor.constraint(equalToConstant: 100)
        ])
    }
}

A small change but now we can customize the properties of our custom view. 😎

This is useful when we are working with a design that reuses the same elements in more than one screen. Or when we notice that some views are very similar with subtle differences.

Review on Initializers

In Class Activity - 20 min

Recreate the example to make a custom view.

Your custom view should:

  • Specify background color
  • Include a corner radius property
self.layer.masksToBounds = true
self.layer.cornerRadius = //value for the corner radius

Then create two instances of your custom view in the View Controller.

sample

xib files

xib files are a great way to create custom views with some benefits from the storyboard.

We can design in the Interface Builder and then use the view in a storyboard or programmatically.

xib files reduce the need of having storyboards and because of this, reduce the amount of bugs too.

xibs or nibs?

Both terms mean a custom view that you can reuse in your project.

XIB (XML Interface Builder) is a representation before the compiler turns it into NIB (NeXTSTEP Interface Builder).

XIBs are easier for us to read while NIBs are easier for the computer to process.

xib files

<iframe src="https://www.youtube.com/embed/ukuwrJmsMB4" data-autoplay width="700" height="500"></iframe>

Demo Pt. 2

Written Tutorial

Lab

Use Custom Views programmatically to refactor your current Onboarding solution. These will replace the content in the scroll view.

Custom Views should have these properties:

  • backgroundColor → UIColor

  • imageName → String

  • message → String

  • isLastPage → Bool

  • A possible solution to the onboarding flow and how to use custom views: video (early 2020).

Additional Resources