如圖所示的多表視圖是一個(gè)很常用的東西讥脐,之前我是用UIScrollView
和UITableViewController
做的笤妙。把當(dāng)前的控制器作為一個(gè)父控制器皂岔,添加三個(gè)UITableViewController
的實(shí)例作為子控制器症见,把父控制器中的 scrollView 作為容器,然后添加子控制器中的 tableView 作為子視圖呼胚。這樣做有一個(gè)問題,一旦有十幾二十個(gè)表的話息裸,內(nèi)存就要爆炸了蝇更。解決的辦法是可以自己寫個(gè)重用機(jī)制沪编,不過這顯然沒必要,用自帶重用機(jī)制的UICollectionView
應(yīng)該是個(gè)更好的選擇年扩。
首先新建個(gè)HomeContainerViewController
蚁廓,繼承自UICollectionViewController
,然后在viewDidLoad
里面加上這兩句:
collectionView?.pagingEnabled = true
collectionView?.bounces = false
這樣滑動(dòng)的時(shí)候就會(huì)有翻頁的段落感厨幻,滑到邊界的時(shí)候也不會(huì)有回彈效果相嵌。
然后要用 layout 控制布局,用最常用的 UICollectionViewFlowLayout
就行了况脆,設(shè)置單元格的寬高饭宾,既然是翻頁,寬肯定是跟屏幕等寬漠另,高度就看你需求了捏雌,但是不要超過 collectionView 的高,如下:
lazy var layout: UICollectionViewFlowLayout = {
let lazyLayout = UICollectionViewFlowLayout()
lazyLayout.itemSize = CGSize(width: Width, height: Height)
lazyLayout.minimumInteritemSpacing = 0
lazyLayout.minimumLineSpacing = 0
lazyLayout.scrollDirection = .Horizontal
return lazyLayout
}()
之后就可以用這個(gè) layout 來初始化之前定義的HomeContainerViewController
笆搓。接下來我們要自定義一個(gè)UICollectionViewCell
性湿,讓它包含一個(gè) tableView:
class HomeCollectionViewCell: UICollectionViewCell {
var tableView: UITableView!
var dataSource: HomeTableDataSource!
override init(frame: CGRect) {
super.init(frame: frame)
tableView = UITableView(frame: bounds, style: .Grouped)
tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: CellReuseIdentifier.LatestArticles)
addSubview(tableView)
dataSource = HomeTableDataSource()
tableView.dataSource = dataSource
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
這邊還有一個(gè) dataSource
(同理可自行添加 delegate),是 tableView 的數(shù)據(jù)源满败,可能大部分人習(xí)慣把控制器又當(dāng) dataSource 又當(dāng) delegate肤频,不過我比較喜歡分開,就算是用同一個(gè)控制器算墨,也會(huì)用extension
把代碼分開宵荒。好現(xiàn)在我們看看如何定義這個(gè) dataSource:
class HomeTableDataSource: NSObject, UITableViewDataSource {
var cellData: String?
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 20
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(CellReuseIdentifier.LatestArticles, forIndexPath: indexPath)
//Configure the cell...
cell.textLabel?.text = cellData
return cell
}
}
注意一定要繼承 NSObject
,因?yàn)?UITableViewDataSource
協(xié)議是繼承了NSObjectProtocol
協(xié)議的净嘀,所以如果你不繼承NSObject
的話报咳,還得自己寫一堆方法來遵守NSObjectProtocol
協(xié)議。因?yàn)檫@邊只是個(gè) Demo挖藏,所以我直接在 cell 中顯示cellData
的值暑刃,那cellData
的值在哪里設(shè)置呢?顯然是在HomeContainerViewController
中:
let tableViewDataList = ["first table", "second table", "third table"]
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! HomeCollectionViewCell
// Configure the cell
cell.dataSource.cellData = tableViewDataList[indexPath.section]
cell.tableView.reloadData()
return cell
}
在真實(shí)場(chǎng)景中一般是會(huì)在 dataSource 中放一個(gè) urlString
的屬性膜眠,然后一旦這個(gè)屬性被賦值就自動(dòng)聯(lián)網(wǎng)取數(shù)據(jù)岩臣。這邊 cell 是會(huì)被復(fù)用的,在翻到第三頁時(shí)宵膨,會(huì)復(fù)用第一頁的 cell 架谎,第四頁復(fù)用第二頁的 cell……依此類推,所以需要給 cell 中的tableView
調(diào)用 reloadData
方法辟躏,不然就算改變了表中的數(shù)據(jù)谷扣,也不能正確的顯示(奇數(shù)頁都顯示第一頁的數(shù)據(jù),偶數(shù)頁都顯示第二頁的數(shù)據(jù))捎琐。
這樣就完成了一個(gè)多表視圖会涎,實(shí)際項(xiàng)目一般會(huì)在 table 上方放個(gè)小滑塊指示器什么的涯曲,也很簡(jiǎn)單,只要在cellForItemAtIndexPath
方法中根據(jù)indexPath.section
來設(shè)置滑塊位置就好了在塔。