2017年9月18日月曜日

Swift3 で UITableView を使う方法

概要

基本中の基本なのですが、delete とか dataSource の使い方を忘れてしまうのでメモとして残しておきます

環境

  • macOS X 10.12.6
  • Xcode 8.3.3 (8E3004b)

プロジェクト作成

Single View Application で作成しましょう

Main.storyboard で UI を作成する

すでに作成されている ViewController に追加していきます

UITableView を追加

まず View があるので、その配下に UITableView を追加します
上下左右の Constraints を 0 で設定しましょう
swift3_basic_uitableview1.png

UITableViewCell を追加

その配下に UITableViewCell を追加しましょう
Identifier にセル識別する ID を設定しておきます
今回は「cell」としました
swift3_basic_uitableview2.png

またセルの高さもここで設定できるので設定しておきます
今回は「100」としました

ContentView 配下にコンテンツを追加

セルに表示するコンテンツを追加していきます
今回はよくある定番の画像とラベルを追加します
UILabel と UIImageView を右ペインの一覧から引っ張ってきて配置しましょう
でここでポイントですが、ContentView 内に配置したコンテンツには Constrainsts をしっかり設定しましょう
今回は左に画像を右にラベルを配置するように Constraints を設定しました

ここの Constraints を設定するのが結構たいへんでセルが狭いと Constraints を設定したときに UIImageView と UILabel が重なっているせいで制約が親の View になってしまったりします
なので初めに手動で各種コンテンツを配置したい場所にだいたい配置して、そのあとで Constraints を設定することで Xcode が良い感じに設定してくれるようになります (言葉で説明するのが難しい、、、)

あと設定しなければいかないのは Tag です
各コンテンツに数字のタグを付与することができます
swift ファイル側で各コンテンツを取得する際に必要になるので必ず設定しましょう
またタグはデフォルトが 0 になっていて 0 は使えないので必ず 1 から設定するようにしてください
今回は UIImageView を 1、UILabel を 2 にしました

最終的には以下のようになれば OK です
swift3_basic_uitableview3.png

セルの高さを 100 にしたので UIImageView の高さも Constraints で 100 にしました

delegate と dataSource を紐付ける

ちょっとややこしいので UITableView を選択した状態で Ctrl を押しながら黄色の丸にドロップアンドドロップしてください
すると delegate と dataSource という項目が出るので 2 つとも UITableView に紐付けましょう
swift3_basic_uitableview5.png

紐付けできると右ペインの Outlets の項目に delegate と dataSource が追加されているのがわかると思います

ViewController.swift でテーブル情報を操作する

これもデフォルトである ViewController を使っていきます
Single View Application でプロジェクトを作成した場合 Main.storyboard にある UIViewController のクラスがデフォルトで ViewController.swift になっています

tableView を swift に追加する

画面を分割して storyboard 側から Ctrl を押したまま UITableView の情報をドラックアンドドロップすれば OK です
以下の 1 行が swift 側に追加されれば OK です

@IBOutlet weak var tableView: UITableView!

swift3_basic_uitableview4.png

UITableViewDelegate を継承して必要な関数を実装する

あとは実際にテーブル情報にコンテンツを表示するロジックを swift 側に記載していきます

まず全体のコードはこちら

  • ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!
    let pokemons = [
        [
            "name": "モクロー",
            "image": "http://www.pokemon.co.jp/ex/sun_moon/common/images/pokemon/partner_01/portrait.png"
        ],
        [
            "name": "ニャビー",
            "image": "http://www.pokemon.co.jp/ex/sun_moon/common/images/pokemon/partner_02/portrait.png"
        ],
        [
            "name": "アシマリ",
            "image": "http://www.pokemon.co.jp/ex/sun_moon/common/images/pokemon/partner_03/portrait.png"
        ]
    ]

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // Cell の数を返却します
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        return pokemons.count
    }

    // Cell の情報を生成します
    func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: IndexPath) -> UITableViewCell {
        let pokemon = pokemons[indexPath.row]
        // Identifier を元にセルを取得
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell")! as UITableViewCell
        // タグ番号 1 で UIImageView インスタンスの生成
        let url = URL(string: pokemon["image"]!)
        let data = try? Data(contentsOf: url!)
        let image: UIImage = UIImage(data: data!)!
        let imageView = cell.viewWithTag(1) as! UIImageView
        imageView.image = image
        // タグ番号 2 で UILabel インスタンスの生成
        let name = cell.viewWithTag(2) as! UILabel
        name.text = pokemon["name"]
        return cell
    }

    // Cell の高さを返却します, StoryBoard の TableView の高さと同じにする必要があります
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }
}

まず UITableViewDelegate を継承します
そして最低限必要なメソッドを 3 つ定義します「numberOfRowsInSection」「cellForRowAtIndexPath」「heightForRowAt」

numberOfRowsInSection はテーブル内に含まれるセルの数を返却する関数です
基本はテーブルに表示する配列などのサイズを返します

cellForRowAtIndexPath はテーブル内のセルにコンテンツを表示する関数です
index が引数で受け取れるのでこの引数を元に UITableViewCell の情報を取得します
そして取得したセル情報のタグ情報をもとに viewWithTag メソッドを使ってコンテンツ表示用の View を取得します
あとはコンテンツ情報をそれぞれの View にセットし最後に cell を返却することでセルにコンテンツが表示されます

heightForRowAt はセルの高さを返す関数です
Main.storyboard 側でも定義していると思いますが関数も定義しましょう

他にも使える関数はたくさんあるので詳しくは参考サイトにある Apple 公式のドキュメントを御覧ください

ATS について

今回はとりあえず ATS を off にしました
Targets を開いて Info に「App Transport Security Settings」->「Allow Arbitrary Loads」を「YES」に設定しています

本当ならちゃんと http するドメインを登録する必要があります

動作確認

あとは実行するだけです
今回は 3 つしかコンテンツがありませんが画面外の場合もちゃんとスクロールすれば表示されます
swift3_basic_uitableview6.png

最後に

Swift3 での UITableView の使い方を紹介しました
iOS アプリの開発手法としてはかなり初歩的なやり方になるかなと思います
結構複雑そうには見えますが、慣れれば簡単に使えるようになると思います

ちなみに今回のようにセルで画像を表示する方法はダメな方法です
これだとセルが表示されるたびに通信をするので大量にスクロールするとアプリがダウンすると思います
本来であれば画像を一度ダウンロードしたらメモリなどにキャッシュしてキャッシュがある場合はそれを表示するようなロジックが必要になります

過去にそれを解決する手法も紹介しているので興味があれば御覧ください

参考サイト

1 件のコメント:

  1. delete と dataSource を紐付けるのは UITableView ではなく View Controller と紐付けてください
    むしろ UITableView にドラッグしても紐付けできないと思います

    返信削除