原文連接:Swift 實現多個 TableView 的側滑與切換(模擬 instagram 系列)
模擬 instagram 項目源碼:github 倉庫:模擬 instagramios關鍵詞:Swift,實現多個 TableView 的側滑與切換,在 ScrollView 中嵌套多個 TableView,一個頁面顯示兩個 tableview…git
如圖:github
將多個 TableView 放在 ScrollView 裏面,將 ScrollView Paging 設置爲 Enabled,實現多個 TableView 的側滑與切換。swift
上方的 tab 標籤跟隨 ScrollView.offset.x 進行動畫,藍條爲單獨繪製的一個長方形 UIView。app
經過 UIButton 的 IBAction 中的動畫,實現點擊 tab 標籤滑動到對應 TableView。ide
1. storyboard動畫
添加一個 UIView,高度設置爲 30px,上左右與 superview 間距爲 0。在裏面放置兩個 UIButton。將兩個 UIButton 組合成 StackView,設置 StackView 上下左右與 superview 間距爲 0,設置 Distribution 爲 Fill Equally。spa
在 storyboard 建立好 ScrollView 和兩個 TableView。在 TableView 中建立好 TableViewCell 模板,而且將對應的類和 reuse identifier 設置好(固然你能夠新建 xib 文件,而後在代碼裏設置 reuse identifier)。兩個 TableView 應該是 ScrollView 的子視圖。code
若是你是在 storyboard 裏面給 TableView 添加 Prototype Cells,記得給每一個 TableView 添加各自的 Prototype Cells。若是隻給其中一個添加 Prototype Cells,那麼另外一個不會自動添加 reuse identifier。在 cellForRowAtIndexPath 方法中,對未添加 Prototype Cells 的 TableView 調用 dequeReusableCellWithIdentifier 時會報錯,由於那個 TableView 原本就沒有嘛。orm
設置 ScrollView 的約束,本項目爲下左右間距均爲 0,上間距爲 1(用於顯示上邊 tab 標籤欄的陰影)。
TableView 的約束不用設置,由於咱們要在代碼中給他們從新定位。
設置好各個 Prototype Cell 的約束。
2. FourthViewController.swift(對應的 viewController)
所有代碼以下:
// // FourthViewController.swift // Instagram // // Created by Ant on 3/31/16. // Copyright © 2016 Ant. All rights reserved. // import UIKit class FourthViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate { @IBOutlet weak var tableViewLeft: UITableView! @IBOutlet weak var tableViewRight: UITableView! @IBOutlet weak var tabPanel: UIView! @IBOutlet weak var followBtn: UIButton! @IBOutlet weak var youBtn: UIButton! @IBOutlet weak var scrollView: UIScrollView! let scrollBar = UIView() var notifications: [Notification] = [] override func viewDidLoad() { super.viewDidLoad() //建立模擬數據 let notification1 = Notification(from: "CHENGKANG", fromAvatar: UIImage(named: "IMG_8040")!, to: "Deer", toAvatar: UIImage(named: "test")!, type: "like", images: [UIImage(named: "test")!, UIImage(named: "test")!, UIImage(named: "test")!, UIImage(named: "test")!, UIImage(named: "test")!, ], date: "3天前") let notification2 = Notification(from: "CHENGKANG", fromAvatar: UIImage(named: "IMG_8040")!, to: "Deer", toAvatar: UIImage(named: "test")!, type: "like", images: [UIImage(named: "test")!], date: "3天前") //添加模擬數據 self.notifications.append(notification1) self.notifications.append(notification2) //初始化要用到的參數 let WIDTH = self.view.frame.width let HEIGHT = self.view.frame.height - 60 - 30 - 49 //設置 tab 標籤面板底部陰影 self.tabPanel.layer.shadowColor = COLOR_GREY.CGColor self.tabPanel.layer.shadowRadius = 0.5 self.tabPanel.layer.shadowOffset = CGSizeMake(0, 0.5) self.tabPanel.layer.shadowOpacity = 1 //添加 tab 標籤面板底部藍條 self.view.addSubview(self.scrollBar) self.scrollBar.backgroundColor = COLOR_LIGHT_BLUE self.scrollBar.frame = CGRectMake(0, 87, WIDTH / 2, 3) //初始化按鈕顏色 self.followBtn.setTitleColor(COLOR_LIGHT_BLUE, forState: .Normal) //設置 scrollView delegate self.scrollView.delegate = self //設置 tableViewLeft delegate,並消除多餘分割線 self.tableViewLeft.delegate = self self.tableViewLeft.dataSource = self self.tableViewLeft.tableFooterView = UIView() //設置 tableViewRight delegate,並消除多餘分割線 self.tableViewRight.delegate = self self.tableViewRight.dataSource = self self.tableViewRight.tableFooterView = UIView() //設置 scrollView contentSize self.scrollView.contentSize = CGSizeMake(WIDTH * 2, HEIGHT) //設置兩個 tableView 大小位置 self.tableViewLeft.frame = CGRectMake(8, 0, WIDTH - 16, HEIGHT) self.tableViewRight.frame = CGRectMake(WIDTH + 8, 0, WIDTH - 16, HEIGHT) } func numberOfSectionsInTableView(tableView: UITableView) -> Int { return 1 } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { //能夠經過判斷當前 tableView 是否與某一個 TableView 相同來給定對應內容 // if tableView == self.tableViewRight { // if self.notifications[indexPath.row].images.count == 1 { // let cell = LikeWithPicCell() // cell.initCell(self.notifications[indexPath.row]) // return cell // } else { // let cell = LikeWithPicsCell() // cell.initCell(self.notifications[indexPath.row]) // return cell // } // } if self.notifications[indexPath.row].images.count == 1 { let cell = tableView.dequeueReusableCellWithIdentifier("LikeWithPicCell") as! LikeWithPicCell cell.initCell(self.notifications[indexPath.row]) return cell } else { let cell = tableView.dequeueReusableCellWithIdentifier("LikeWithPicsCell") as! LikeWithPicsCell cell.initCell(self.notifications[indexPath.row]) return cell } } func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if tableView == self.tableViewRight { //此處 -1 是爲了讓展現內容有區分,由於用的相同數據 return self.notifications.count - 1 } return self.notifications.count } func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return UITableViewAutomaticDimension } func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { return UITableViewAutomaticDimension } func scrollViewDidScroll(scrollView: UIScrollView) { //判斷當前 scrollView 是咱們項目中的 ScrollView 而非那兩個 tableView if scrollView == self.scrollView { //改變 scrollBar x 座標,達成同步滑動效果。 let offsetX = scrollView.contentOffset.x self.scrollBar.frame = CGRectMake(offsetX / 2, 87, self.view.frame.width / 2, 3) //對應修改 btn 文字顏色 if offsetX > self.view.frame.width / 2 { self.followBtn.setTitleColor(UIColor.blackColor(), forState: .Normal) self.youBtn.setTitleColor(COLOR_LIGHT_BLUE, forState: .Normal) } else { self.followBtn.setTitleColor(COLOR_LIGHT_BLUE, forState: .Normal) self.youBtn.setTitleColor(UIColor.blackColor(), forState: .Normal) } } } @IBAction func followBtnPressed(sender: UIButton) { //點擊按鈕時,經過動畫移動到對應 tableView UIView.animateWithDuration(0.3, delay: 0, options: [.CurveEaseInOut], animations: { () -> Void in self.scrollView.contentOffset.x = 0 }, completion: nil) } @IBAction func youBtnPressed(sender: UIButton) { //點擊按鈕時,經過動畫移動到對應 tableView UIView.animateWithDuration(0.3, delay: 0, options: [.CurveEaseInOut], animations: { () -> Void in self.scrollView.contentOffset.x = self.view.frame.width }, completion: nil) } }
在這個項目中,我懶因此兩個 TableView 用的相同的 Prototype Cell 和同一組數據,而後在返回第二個 TableView cell 個數時 -1,好在顯示時區分兩者。
當在一個 ViewController 裏面包含多個 TableView 的時候,使用 TableView Delegate 提供的方法時,能夠經過判斷參數 tableView 是否與項目中對應 TableView 相同來執行對應操做。如上面代碼中提到的:
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if tableView == self.tableViewRight { //此處 -1 是爲了讓展現內容有區分,由於用的相同數據 return self.notifications.count - 1 } return self.notifications.count }
同上,有多個 scrollView 時,一樣方法斷定當前是哪一個 scrollView。
UITableView 爲 UIScrollView 的子類。若是添加了 scrollView delegate,不進行判斷的話,可能會出現上下滑動 tableView 時觸發 scrollViewDidScroll 方法,致使在第二頁時上下滑動時 tab 標籤切換到第一個標籤。
不要忘記設置 scrollView.delegate
不要忘記設置 scrollView.contentSize
經過設置空白 tableFooterView 爲空白 UIView,消除多餘分割線。