Swift 實現多個 TableView 的側滑與切換(模擬 instagram 系列)

原文連接: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,好在顯示時區分兩者。

須要注意的幾點

  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
    }
  2. 同上,有多個 scrollView 時,一樣方法斷定當前是哪一個 scrollView。

  3. UITableView 爲 UIScrollView 的子類。若是添加了 scrollView delegate,不進行判斷的話,可能會出現上下滑動 tableView 時觸發 scrollViewDidScroll 方法,致使在第二頁時上下滑動時 tab 標籤切換到第一個標籤。

  4. 不要忘記設置 scrollView.delegate

  5. 不要忘記設置 scrollView.contentSize

  6. 經過設置空白 tableFooterView 爲空白 UIView,消除多餘分割線。

相關文章
相關標籤/搜索