ios在ScrollView中嵌套多個TableView

說明:示例在XCode7 beta5完成

創建一個Single View Application,填寫相應的信息. Language選擇Swift,把項目存儲到一個目錄,單擊Create完成創建.

Storyboard設計階段
  1. 打開Main.storyboard文件,取消勾選Use Size Classes,讓設計視圖呈現iphone的大小.



    下面是取消勾選后,設計面板的樣子.



    現在開始在storyboard中添加要使用到的控件.
    從控件庫中拖出一個Segmented Control到設計面板的上方.

    選中Segmented Control,給它增加如下約束.



    接下來拖一個ScrollView到到設計面板中,讓它鋪滿剩余的空間.

    同樣也要給ScrollView增加約束,這樣才可以適應不同屏幕的大小.

    接著拖一個TableView到設計面板中,放置在ScrollView上,成為ScrollView的子視圖.

    調整它的大小,讓它的大小和ScrollView的相同.

    現在給TableView加上約束.



    此時設計面板中多了一些紅色的線條,這說明缺少約束或者約束有沖突.

    通過以下步驟來增加約束,這樣storyboard就有足夠的信息來確定控件的位置關系.點擊Document Outline左上方的紅色小圓圈,在點擊空心的紅色小圓圈,在彈出框中選擇Add Missing Constraints.

    接著個體TableView增加一個Prototype Cell.

    然后展開TableView選中Table View Cell,給它設置一個重用ID.

    為了區分接下來要添加的TableView,選中當前的TableView,給它設置一個tag,這里設置為101,再給它取一個名字.

    接下來添加第二個TableView,為了方便操作,在控件庫中直接把TableView拖放至Document Outline中,讓它位于ScrollView的下方,成為ScrollView的子視圖.

    使用相同的方式給剛剛添加的TableView設置一個tag,這里設置為102,給它取一個名字,叫做SecondTableView.再給SecondTableView增加一個Prototype Cell,并設置它的reused identifier為second.
    接下來這一步比較關鍵,要改變SecondTableView的位置,這樣才能給SecondTableView添加上正確的約束.把SecondTableView的x坐標設置為320,完成后,會把SecondTableView移動到設計面板之外,如下所示.

    現在選中SecondTableView為它增加約束.

    此時又出現了紅色的線條.沒關系,有這個方法讓紅色線條消失.選中FirstTableView,按住ctrl鍵,鼠標左鍵從FirstTableView拖出一條箭頭到SecondTableView,松開鼠標在彈出菜單中選擇Equal Widths.這樣做的結果是,兩個TableView具有相同的寬度.

    ok,到此為止,storyboard的設計工作完成,接下來進入代碼階段.

代碼階段

打開輔助視圖,為設計面板中的控件生成相應的outlet.同時為Segmented Control綁定一個Action,它的事件類型為Value Changed,可以把Segmented Control上的items當作獨立的button來使用.



完成后,代碼文件會類似于這樣.

import UIKit
class ViewController: UIViewController {
    // 1. 拖拽生成控件的outlet
    @IBOutlet weak var segmented: UISegmentedControl!
    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var firstTableView: UITableView!
    @IBOutlet weak var secondTableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
       
    }

    // 2. 當Segmented Control選擇的item改變時,會觸發這個Action
    @IBAction func tabChanged(sender: AnyObject) {

    }
}

為了不讓Segmented Control給狀態欄遮擋,在viewDidLoad()函數的下方,添加以下代碼,把狀態欄隱藏掉.

// 3. 隱藏狀態欄
    override func prefersStatusBarHidden() -> Bool {
        return true
}

讓當前ViewController遵循UITableViewDataSource協議,這樣就能夠給TableView提供數據.類定義的頭部將會是下面的樣子.
class ViewController: UIViewController, UITableViewDataSource
這里為什么不讓ViewController遵循UITableViewDelegate協議呢.因為這個例子只是給TableView填充數據,并不處理發生在TableView上的行為事件.
接著實現兩個代理方法,為TableView填充數據.把這兩個方法添加在prefersStatusBarHidden()函數的下方.

// 4. 為TableView填充數據
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var reusedID: String!
        
        if tableView.tag == 101 {
            reusedID = "first"
        }
        else {
            reusedID = "second"
        }
        
        let cell = tableView.dequeueReusableCellWithIdentifier(reusedID) as UITableViewCell!
        
        if tableView.tag == 101 {
            cell.textLabel!.text = "第一個TableView"
        }
        else {
            cell.textLabel!.text = "第二個TableView"
        }
        
        return cell
    }

這里利用tag來判斷是哪一個TableView,然后使用設置好的reused identifier來獲取到cell,給cell的textLabel設置簡單的字符串.
在viewDidLoad()函數中,添加以下兩行代碼.這樣TableView的代理方法將會由當前的ViewController來執行.

firstTableView.dataSource = self
secondTableView.dataSource = self

選擇一個模擬器,運行一下看有什么效果.



第一個TableView已經呈現出來了,試著往左滑動,把第二個TableView呈現出來.滑了幾次,發現不能將SecondTableView呈現出來,為什么會這樣呢??難道SecondTableView沒有添加到ScrollView中.利用前面添加的Action來做個實驗,看是否把SecondTableView添加到了ScrollView中.
首先viewDidLoad()函數的上方,定義一個變量,用來記錄ScrollView的內容偏移量.

// 5. 定義一個變量來記錄scrollview的內容偏移量
    var offset: CGFloat = 0.0 {
        
        // 當offset的值改變后會執行didSet代碼塊
        didSet {
            UIView.animateWithDuration(0.3) { () -> Void in
                self.scrollView.contentOffset = CGPoint(x: self.offset, y: 0.0)
            }
        }
    }

didSet代碼塊的作用是,用一個0.3秒的過度來設置ScrollView的內容偏移量.
接著在 tabChanged(sender: AnyObject) Action中添加以下代碼.

// a. 獲取到當前item的下標
let index = (sender as! UISegmentedControl).selectedSegmentIndex
// b. 設置scrollview的內容偏移量
offset = CGFloat(index) * self.view.frame.width

item的下標從0開始.因為TableView的寬度和屏幕的寬度相同,所以呈現FirstTableView時ScrollView的內容偏移量為0,呈現SecondTableView時ScrollView的內容偏移量為一個屏幕的寬度,即(self.view.frame.width).
再運行一遍程序,當點擊Second item時,可以把SecondTableView呈現出來,說明有把SecondTableView加到ScrollView中.



到這個階段的完整代碼如下.

import UIKit
class ViewController: UIViewController, UITableViewDataSource {
    // 1. 拖拽生成控件的outlet
    @IBOutlet weak var segmented: UISegmentedControl!
    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var firstTableView: UITableView!
    @IBOutlet weak var secondTableView: UITableView!
    
    // 5. 定義一個變量來記錄scrollview的內容偏移量
    var offset: CGFloat = 0.0 {
        
        // 當offset的值改變后會執行didSet代碼塊
        didSet {
            UIView.animateWithDuration(0.3) { () -> Void in
                self.scrollView.contentOffset = CGPoint(x: self.offset, y: 0.0)
            }
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
       
        firstTableView.dataSource = self
        secondTableView.dataSource = self
        
    }
    
    // 2. 當Segmented Control選擇的item改變時,會觸發這個Action
    @IBAction func tabChanged(sender: AnyObject) {
        // a. 獲取到當前item的下標
        let index = (sender as! UISegmentedControl).selectedSegmentIndex
        
        // b. 設置scrollview的內容偏移量
        offset = CGFloat(index) * self.view.frame.width
    }
    
    // 3. 隱藏狀態欄
    override func prefersStatusBarHidden() -> Bool {
        return true
    }
    
    // 4. 為TableView填充數據
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var reusedID: String!
        
        if tableView.tag == 101 {
            reusedID = "first"
        }
        else {
            reusedID = "second"
        }
        
        let cell = tableView.dequeueReusableCellWithIdentifier(reusedID) as UITableViewCell!
        
        if tableView.tag == 101 {
            cell.textLabel!.text = "第一個TableView"
        }
        else {
            cell.textLabel!.text = "第二個TableView"
        }
        return cell
    }
}

為什么滑動操作不成功呢,網上看到有人說TableView繼承自ScrollView,那么滑動手勢很可能在TableView攔截了,因此為ScrollView增加兩個滑動手勢識別器.
在viewDidLoad()函數中添加以下代碼.

// 6. 為scrollView增加滑動手勢識別器
        let swipeLeft = UISwipeGestureRecognizer(target: self, action: "swipe:")
        swipeLeft.direction = .Left
        swipeLeft.numberOfTouchesRequired = 1
        
        let swipeRight = UISwipeGestureRecognizer(target: self, action: "swipe:")
        swipeRight.direction = .Right
        swipeRight.numberOfTouchesRequired = 1
        
        scrollView.addGestureRecognizer(swipeLeft)
        scrollView.addGestureRecognizer(swipeRight)

定義了兩個滑動的手勢識別器,方向分別向左和向右,numberOfTouchesRequired的意思是只要單點觸摸就可以完成滑動操作.
把swipe()函數添加到最后一個花括號的上方.

// 滑動手勢處理函數
    func swipe(gesture: UISwipeGestureRecognizer) {
        
        if gesture.direction == .Left {
            // 向左滑時展示第二個tableview,同時設置選中的segmented item
            offset = self.view.frame.width
            segmented.selectedSegmentIndex = 1
        }
        else {
            offset = 0.0
            segmented.selectedSegmentIndex = 0
        }
    }

0k,代碼階段也結束了.
運行一下程序, 左右滑動可以呈現不同的TableView,選中的segmented item也會跟著改變.
圖片加載不出來的話, 這里有pdf格式的,提取碼:84e9

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,591評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,554評論 2 379

推薦閱讀更多精彩內容