【swift】無限スクロールするUItableViewを実装する方法メモ
はじめに
今回やりたかったのは、またありがちなこんな感じの画面です。
といってもやりたかったのは、こちらで書いた内容をコードレベルにしたもので。
【swift】uitableviewが重いときに対処すべき2つのこと - とりあえずphpとか
UITableViewを使うときにパフォーマンス面で気をつけるということでした(なめらかになるにしたかった)
あとは、行によってテーブルセルの高さを動的に変更することでしょうか
上の記事とかぶりますがやっぱり以下がポイントかとおもいます
・1度高さを計算した行は何度も計算し直さない
・セルの高さ計算用のオブジェクトを用意して使い回す
実装方法
ViewController.swift
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { var tableView: UITableView = UITableView() var tableData = [Dictionary<String, AnyObject>]() // API等からデータを取得するためのクラス var model: Model = Model() // セルの高さ計算用のテーブルセル ★ここがポイント var calcCell = CustomTableViewCell() // セルの高さ保持用の配列 ★ここがポイント var cacheCellHeight = [CGFloat]() // 読み込み中フラグ var isLoading: Bool = false override func viewDidLoad() { super.viewDidLoad() // データ取得 self.isLoading = true model.get { (result) -> Void in self.callback(result) } // VIEWをセットします setView() } // VIEWをセットします func setView() { // ・・・ //テーブルビューのおきまりの処理とか tableView.registerClass(CustomTableViewCell.self, forCellReuseIdentifier: "CustomCell") self.view.addSubview(tableView) } func callback(result: [Dictionary<String,AnyObject>]) { for var i = 0; i < result.count; i++ { self.tableData.insert(result[i], atIndex: self.tableData.count) } self.isLoading = false self.tableView.reloadData() } // 1番したまでスクロールしたらデータ取得 func scrollViewDidScroll(scrollView: UIScrollView) { var contentOffsetWidthWindow = self.tableView.contentOffset.y + self.tableView.bounds.size.height var eachToBottom = contentOffsetWidthWindow >= self.tableView.contentSize.height if (!eachToBottom || self.isLoading) { return; } self.isLoading = true model.get { (result) -> Void in self.callback(result) } } // テーブルセルの高さをかえします ★ここがポイント func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { if cacheCellHeight.count - 1 >= indexPath.row { return cacheCellHeight[indexPath.row] } else { var height = self.calcCell.setData(tableData[indexPath.row]) cacheCellHeight.insert(height, atIndex: indexPath.row) return height } } // テーブルの行数をかえします func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.tableData.count } }
CustomTableViewCell.swift
カスタムテーブルビューセルで画面にデータをセットすることと、高さをかえすのが役割
class CustomTableViewCell: UITableViewCell { var icon = UIImageView() var title = UILabel() var content = UILabel() override init(style: UITableViewCellStyle, reuseIdentifier: String!) { super.init(style: style, reuseIdentifier: reuseIdentifier) self.setUp() } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) self.setUp() } func setUp() { self.addSubview(icon) self.addSubview(title) self.addSubview(content) } // データをセットして高さを返します func setData(data: Dictionary<String,AnyObject>) -> CGFloat { var widthMax: CGFloat = self.frame.width var heightMax: CGFloat = self.frame.height icon.frame = CGRectMake(5, 5, 48, 48) icon.image = UIImage(named: data["icon"] as! String) title.frame = CGRectMake(icon.frame.origin.x + icon.frame.size.width + 5, 5, widthMax - (5 + icon.frame.size.width + 5 + 5), 20) title.font = UIFont.boldSystemFontOfSize(15) title.text = data["name"] as? String content.frame = CGRectMake(title.frame.origin.x, title.frame.origin.y + title.frame.size.height + 5, title.frame.size.width, 0) content.numberOfLines = 0 content.font = UIFont.systemFontOfSize(13) content.text = (data["content"] as? String)! + (data["content"] as? String)! + (data["content"] as? String)! content.sizeToFit() var height: CGFloat = content.frame.origin.y + content.frame.size.height + 5 return height } }
Model.swift
APIからデータを取得する擬似的なクラス
class Model: NSObject { func get(callback:(result: [Dictionary<String,AnyObject>]) -> Void) { var result: [Dictionary<String, AnyObject>] = [] for var i = 0; i < 50; i++ { var n = Int(arc4random() % 5 + 1) var m = Int(arc4random() % 3 + 1) var content = "" for var j = 0; j < n; j++ { content = content + "コメントコメントコメント" } var dictionary: Dictionary<String, AnyObject> = [ "icon": "icon" + String(m) + ".jpg", "name": "ユーザー名", "content": content, ] result.insert(dictionary, atIndex: result.count) } callback(result: result) } }
ずらずらかきましたが以上です