【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)
}
}ずらずらかきましたが以上です