wift - Xibを利用してTableViewとカスタマイズcellを作成する


はじめに

恐らくtableviewなら、普通のやり方だけでいけるのに、
どうしてわざわざ手間をかけてxibを使うの?
どんなタイミングで使うの?と思う方がいると思います。

シンプルな画面なら普通のやり方で大丈夫だと思いますが、
同じController画面に複数の複雑なメイン画面がある時、このように各画面をパーツ化し、それぞれ組み立てた方がわかりやすくて今後の保守性、拡張性に優しいかもしれませんので、ご参考を!

手順

  • Xibファイルを作成する
  • Xib画面にUITableViewを追加する
  • カスタマイズclassのファイルを作成する
  • cell用のxibファイル、swiftファイルを作成する
  • controller画面のUIViewのclassを定義したclassと設定する
  • viewDidLoadでcellをtableviewに登録する処理を入れる

各ステップに細かい手間があって抜けてはいけないので、以下説明いたします。

Xibファイルを作成する

File -> New -> File...でXibファイルを作成する

Xib画面にUITableViewを追加する

XibのviewにUITableViewを入れる

カスタマイズclassのファイルを作成する

File -> New -> File... -> Swift Fileを選択する
ファイルを作成し、カスタマイズclassを定義してから、xibファイルのFile's Ownerのclassを定義したclassと設定して、以下のように処理を入れる

test.swift
import Foundation
import UIKit

class Test: UIView{
    //xibファイルに追加したUItableViewをswiftファイルと連結するようにする
    @IBOutlet weak var testTableView: UITableView!

    // コードから呼び出す際に使用される
    override init(frame: CGRect) {
        super.init(frame: frame)
        loadNib()
    }

    // Storyboardから利用する際に使用される
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        loadNib()
    }

    // 上記どちらのinitからも使用される共通関数で、xibファイルを呼び出す。
    func loadNib() {
        // 第1引数のnameには、xibファイル名
        // ownerはself固定
        // optionsはここではnil
        let view = Bundle.main.loadNibNamed("test", owner: self, options: nil)?.first as! UIView
        view.frame = self.bounds
        self.addSubview(view)
    }
}

cell用のxibファイル、swiftファイルを作成する

File -> New -> Cocoa Touch Classを選択し、「Also create XIB file」にチェックを入れて、xibファイル、swiftファイル両方作れる。

作った後に、色々UIコンポネートを入れて、Identifierをネーミングする

こちらの場合は二つのラベルを入れたので、swiftファイルと連結するようにする

testTableViewCell.swift
import UIKit

class testTableViewCell: UITableViewCell {

    //swiftファイルと連結するようにする
    @IBOutlet weak var testLb1: UILabel!
    @IBOutlet weak var testLb2: UILabel!


    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

定義したclassを持つUIViewをcontroller画面に入れる

UIViewを入れて、Custom ClassをTestにする。

viewDidLoadにcellをtableviewに登録する処理を入れる

登録する前に、追加したUIViewをswiftファイルと連結するようにする

ViewController.swift
    @IBOutlet weak var testView: Test!

連結した後に、viewDidLoadでcellをtableviewに登録する

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var testView: Test!

    override func viewDidLoad() {
        super.viewDidLoad()
        testView.testTableView.register(UINib(nibName: "testTableViewCell", bundle: nil), forCellReuseIdentifier: "testCell")
    }

}

登録した後に、あとは従来のTableView追加のやり方とほぼ同じ。
UITableViewDelegateUITableViewDataSourceをViewControllerに実装して、dataSourcedelegateをViewControllerに代理させる

ViewController.swift
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
    override func viewDidLoad() {
        super.viewDidLoad()
        testView.testTableView.dataSource = self
        testView.testTableView.delegate = self
        testView.testTableView.register(UINib(nibName: "testTableViewCell", bundle: nil), forCellReuseIdentifier: "testCell")
    }
...

func tableView(_ tableView:numberOfRowsInSection section:) -> Intfunc tableView(_ tableView:cellForRowAt indexPath:) -> UITableViewCellを実装する

ViewController.swift
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //適当に戻す
    return 10
    }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "testCell", for: indexPath) as? testTableViewCell
    else { return UITableViewCell() }
    cell.testLb1.text = "test1"
    cell.testLb2.text = "test2"
    return cell
    }

これで完成!

終わりに

メイン機能だけ説明しました、細かいレーアウトの処理はここで割愛いたします。
tableviewだけではなく、他にさまざまなUIViewでも、このやり方で実装できると思います。
これで説明が終えたいと思います、何か抜けた部分があればコメントいただければと思います。