LoginSignup
38
26

More than 3 years have passed since last update.

XIBファイルを使ってカスタムビューを実装する方法(Swift)

Last updated at Posted at 2020-06-17

はじめに

iOSアプリ開発において、UIを部品化して使い回したい場合、XIBファイルを使って実現することが多いと思います。
実装方法を忘れることが多いので、本記事でまとめることにします。

環境

本記事ではXIBファイルの読み込みにR.swiftを使っています。
R. から始まる処理はR.swiftの記述なので、適宜読み替えてください。

  • OS:macOS Mojave 10.14.6
  • Xcode:11.3.1 (11C504)
  • Swift:5.1.3
  • R.swift:5.2.2

カスタムビューの実装

カスタムビューの実装方法を紹介します。

カスタムビュークラスの作成

まず、 UIView を継承したクラスを作成します。
私は↓をテンプレートとしてコピペしています。

FooView.swift
import UIKit

@IBDesignable
final class FooView: UIView {

    // MARK: Stored Instance Properties

    // MARK: Computed Instance Properties

    // MARK: IBOutlets

    // MARK: Initializers

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

        configureView()
    }

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

        configureView()
    }

    // MARK: IBActions

    // MARK: Other Internal Methods

    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()

        configureView()
    }

    // MARK: Other Private Methods

    private func configureView() {
        loadNib()

        // TODO: 他にUIの装飾処理があれば実行する
    }

    private func loadNib() {
        guard let fooView = R.nib.fooView(owner: self) else {
            fatalError("Fail to load FooView from Nib.")
        }
        fooView.frame = self.bounds
        addSubview(fooView)
    }
}

XIBファイルを編集してビルドしても画面が真っ白になることがありますが、大体はXIBファイルを読み込んで addSubview(_:) していないのが原因です。
忘れやすいので、↑のように自分の中でテンプレート化しておくと便利です。

XIBファイルの作成

このままでは R.nib.fooView(owner: self) でビルドエラーになるので、XIBファイルを作成します。

プロジェクトツリーで右クリック > New File... > iOS - User Interface - View > [Next]ボタンをクリック
スクリーンショット_2020-06-17_19_40_52.jpg

XIBファイル名を入力 > [Create]ボタンをクリック
スクリーンショット_2020-06-17_19_44_00.jpg

XIBファイル名は任意ですが、先ほど作成したカスタムビュークラスと同じにするとわかりやすいです。

XIBファイルのFile's Ownerを設定

XIBファイルのFile's Ownerに、先ほど作成したカスタムビュークラスを指定します。
スクリーンショット_2020-06-17_19_49_34.jpg

忘れやすいので注意です。

XIBファイルから不要なものを非表示

画面全体でなく一部分のみのカスタムビューを作る場合、ViewのSizeを Freeform 、Top BarとBottom Barを None にすると、不要なものが表示されなくなって実装しやすくなります。
スクリーンショット 2020-06-17 21.55.32.png

こちらの設定はあくまでIB上でのみ反映され、実際のアプリには無関係という認識です。
そのため、作りたいカスタムビューに応じて設定を変更するのが望ましいです。

XIBファイルの編集

ここまで来たら好きなように UILabelUIButton などのUIを配置し、カスタムビューを作成します。
必要に応じて IBOutletIBAction でカスタムビュークラスと接続してください。

カスタムビューの使い方

カスタムビューの使い方は、通常のUIと同様です。
StoryboardやXIBファイルに UIView として配置し、Custom Classに指定するのみです。
スクリーンショット_2020-06-17_19_56_45.jpg

カスタムビュークラスに @IBDesignable を付けると、IB上で描画されてデザインが作りやすくなります。

注意

XIBファイルを使う際の注意点を紹介します。

XIBファイルから読み込んだビューはカスタムビューに載せているだけ

例えば、カスタムビュークラスで背景色を以下のように変更しようとします。

FooView.swift
    private func configureView() {
        loadNib()

        backgroundColor = .blue
    }

これだけだと背景色は変わったように見えません。

理由は単純で、 loadNib() 内の処理を見ればわかります。
XIBファイルから読み込んだビューは、カスタムビュークラスのビューの上に追加しているので、いくら背景色を変えてもXIBのビューに隠されて見えないです。

FooView.swift
    private func loadNib() {
        // XIBファイルからビューを読み込む
        guard let fooView = R.nib.fooView(owner: self) else {
            fatalError("Fail to load FooView from Nib.")
        }

        // XIBから読み込んだビューのサイズを、カスタムビュークラスのビューに合わせる
        fooView.frame = self.bounds

        // XIBから読み込んだビューを、カスタムビュークラスのサブビューに追加する
        addSubview(fooView)
    }

図で見るともっとわかりやすいと思います。
先ほどのコードで変えた背景色は、図の斜線部分なので、XIBのビューに隠されていることがわかります。
1592378872334.jpg

解決法は大きく2つあります。

  • XIBファイル上でビューの背景色を透過色にする
    最もかんたんな方法だが、透過色は計算負荷が高いのでパフォーマンスが落ちる可能性がある
  • XIBファイルから読み込んだビューを contentView のような名前でプロパティとして保持し、こちらの背景色を変える
    プロパティとして持たせると、何でも操作できて無駄にスコープが広がる

パフォーマンスが落ちることはめったにないので、私は前者を選ぶことが多いです。

おわりに

これでXIBファイルを使ってカスタムビューを作れるようになりました!
UIを適切な粒度で部品化し、効率よく開発しましょう:relaxed:

もし本記事の内容に誤りや過不足があれば、ご指摘いただけると嬉しいです。
例えばよく見る awakeFromNib() というメソッドを使わずに実現しているので、問題ないのか気になります><

参考リンク

38
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
26