Swift
UIView
iOS Development
SwiftUI
Programming Tutorial

Swift subclass UIView

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Subclassing UIView is the standard UIKit way to build a reusable custom visual component. It is the right tool when you need custom drawing, a self-contained layout, or a view with behavior that would be awkward to assemble repeatedly from stock controls.

Start With the Right Initializers

A custom view should initialize correctly whether it is created in code or loaded from a storyboard or XIB. That usually means implementing both init(frame:) and init(coder:), then calling a shared setup method.

swift
1import UIKit
2
3final class BadgeView: UIView {
4    private let titleLabel = UILabel()
5
6    override init(frame: CGRect) {
7        super.init(frame: frame)
8        commonInit()
9    }
10
11    required init?(coder: NSCoder) {
12        super.init(coder: coder)
13        commonInit()
14    }
15
16    private func commonInit() {
17        backgroundColor = .systemBlue
18        layer.cornerRadius = 12
19
20        titleLabel.translatesAutoresizingMaskIntoConstraints = false
21        titleLabel.textColor = .white
22        titleLabel.font = .boldSystemFont(ofSize: 14)
23        addSubview(titleLabel)
24
25        NSLayoutConstraint.activate([
26            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12),
27            titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12),
28            titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 8),
29            titleLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8),
30        ])
31    }
32
33    func configure(text: String) {
34        titleLabel.text = text
35    }
36}

This pattern prevents duplicated setup logic and makes the class reliable in multiple creation paths.

Know Which Method to Override

A lot of confusion around UIView subclassing comes from overriding the wrong method for the job.

Use layoutSubviews() when the subview frames or constraints need adjustment after the view’s bounds change.

Use draw(_:) when you need custom Core Graphics drawing.

Use intrinsicContentSize when the view knows its natural size and should participate in Auto Layout without fixed external constraints.

These methods solve different problems. For example, drawing a border in draw(_:) and repositioning labels in layoutSubviews() is normal. Rebuilding the whole subview hierarchy in draw(_:) is usually a mistake.

Custom Drawing Example

If the view’s appearance is mostly graphical rather than compositional, draw(_:) may be the cleanest approach.

swift
1import UIKit
2
3final class RingView: UIView {
4    override func draw(_ rect: CGRect) {
5        guard let context = UIGraphicsGetCurrentContext() else { return }
6
7        let insetRect = rect.insetBy(dx: 8, dy: 8)
8        context.setStrokeColor(UIColor.systemGreen.cgColor)
9        context.setLineWidth(6)
10        context.strokeEllipse(in: insetRect)
11    }
12}

Custom drawing is powerful, but it should be used deliberately. If a view can be composed from standard subviews and layers, that is often easier to maintain.

Auto Layout and Sizing

Modern UIKit code should usually be constraint-driven. Avoid hard-coding geometry too early in initialization because the view’s size is not final at that stage.

If your custom view has a natural size, provide it explicitly.

swift
override var intrinsicContentSize: CGSize {
    CGSize(width: 120, height: 40)
}

If the layout depends on dynamic content, call invalidateIntrinsicContentSize() after updating the relevant data.

This is often a better design than exposing frame math to every caller of the view.

When a UIView Subclass Is the Right Choice

A dedicated subclass is a good fit when:

  • the component is reused in many screens
  • the view manages its own state and visual updates
  • drawing or layout is complex enough to deserve isolation
  • the public API can stay small and predictable

A subclass is usually the wrong choice when you only need a one-off screen layout or when a standard UIStackView, UILabel, or UIButton composition already solves the problem cleanly.

Common Pitfalls

The most common mistake is doing layout work in init that depends on the final size of the view. Bounds are often not correct there yet.

Another common issue is overriding draw(_:) for work that is not actually drawing. Subview creation, Auto Layout setup, and data binding belong elsewhere.

Developers also sometimes forget the init(coder:) path, which causes storyboard-loaded views to crash or skip initialization.

Finally, avoid turning a custom view into a miniature view controller. Keep its API focused on presentation and user interaction, and let higher layers own navigation and business logic.

Summary

  • Subclass UIView when you need a reusable component with custom layout, drawing, or behavior.
  • Implement both initializer paths and funnel setup through a shared method.
  • Override layoutSubviews(), draw(_:), and intrinsicContentSize only for their intended responsibilities.
  • Prefer Auto Layout-friendly design over premature frame math.
  • Keep the custom view focused so it remains reusable and easy to test.

Course illustration
Course illustration

All Rights Reserved.