xibとコードの両方から利用できるカスタムビューを作る

xibのイニシャライザと、コードのイニシャライザ

引き続き、下記のアプリで行ったことをアウトプット。

ボルダー

ボルダー

  • masashi sutou
  • スポーツ
  • 無料

xibのイニシャライザは init?(coder aDecoder: NSCoder) で、コードのイニシャライザは init(frame: CGRect) または独自で定義したイニシャライザになる。

上記のアプリを作成したとき、xibとコードの両方から利用できるカスタムViewが欲しくなった。

具体的に説明すると、Cellで画像を表示するViewはCellがStoryboardで定義されているのでxib経由で初期化したい。 一方、上記のアプリは画像や動画を複数同時にアップロード可能で画像Viewの数が一定ではないため、コードで初期化をコントロールしたい。

つまり、UIImageViewを継承したカスタムなイメージビューをxibとコードの両方から呼べるようにして、一つのカスタムビューで対応したいということ。

カスタムビューのイニシャライザ

MediaViewという名前のカスタムビューを作成して対応した。 xibとコードの両方から利用できるように下記のようなイニシャライザにした。 コードはSwift3です。

import UIKit

final class MediaView: UIImageView {

    private(set) var url: URL?
    private let indicator: UIActivityIndicatorView = UIActivityIndicatorView(activityIndicatorStyle: .gray)
    private let playImageView: UIImageView = UIImageView(image: UIImage(named: "play_icon"))

    init() {
        super.init(frame: .zero)
        isUserInteractionEnabled = true
        contentMode = .scaleAspectFit
        clipsToBounds = true
        translatesAutoresizingMaskIntoConstraints = false
        initialize()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialize()
    }
    
    private func initialize() {
        
        indicator.hidesWhenStopped = true
        indicator.isHidden = true
        indicator.translatesAutoresizingMaskIntoConstraints = false
        addSubview(indicator)
        
        playImageView.contentMode = .scaleAspectFit
        playImageView.isHidden = true
        playImageView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(playImageView)
        
        NSLayoutConstraint.activate([
            indicator.centerXAnchor.constraint(equalTo: centerXAnchor),
            indicator.centerYAnchor.constraint(equalTo: centerYAnchor),
            indicator.widthAnchor.constraint(equalToConstant: indicator.frame.width),
            indicator.heightAnchor.constraint(equalToConstant: indicator.frame.height),
            playImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
            playImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
            playImageView.widthAnchor.constraint(equalToConstant: playImageView.frame.width),
            playImageView.heightAnchor.constraint(equalToConstant: playImageView.frame.height)
        ])
    }
    
// 省略

xibとコードの両方で利用されるものをinitialize()というメソッドにまとめた。

コードで利用する場合はframeではなく、AutoLayoutでレイアウトを定義したかったのでtranslatesAutoresizingMaskIntoConstraints = falseにした。

今回はアプリの仕様上、初期化後にレイアウトが不変だったのでinit()で済ましたが、override init(frame: CGRect)にしてframeを渡しても良い。

まとめ

  • xibのイニシャライザは init?(coder aDecoder: NSCoder) で、コードのイニシャライザは init(frame: CGRect) または独自で定義したイニシャライザになる。
  • 例えば、xibとコードの両方で利用されるものをinitialize()というメソッドにまとめて、両方のイニシャライザから呼べば良い。