ios在ScrollView中嵌套多個(gè)TableView

說(shuō)明:示例在XCode7 beta5完成

創(chuàng)建一個(gè)Single View Application,填寫(xiě)相應(yīng)的信息. Language選擇Swift,把項(xiàng)目存儲(chǔ)到一個(gè)目錄,單擊Create完成創(chuàng)建.

Storyboard設(shè)計(jì)階段
  1. 打開(kāi)Main.storyboard文件,取消勾選Use Size Classes,讓設(shè)計(jì)視圖呈現(xiàn)iphone的大小.



    下面是取消勾選后,設(shè)計(jì)面板的樣子.



    現(xiàn)在開(kāi)始在storyboard中添加要使用到的控件.
    從控件庫(kù)中拖出一個(gè)Segmented Control到設(shè)計(jì)面板的上方.

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



    接下來(lái)拖一個(gè)ScrollView到到設(shè)計(jì)面板中,讓它鋪滿剩余的空間.

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

    接著拖一個(gè)TableView到設(shè)計(jì)面板中,放置在ScrollView上,成為ScrollView的子視圖.

    調(diào)整它的大小,讓它的大小和ScrollView的相同.

    現(xiàn)在給TableView加上約束.



    此時(shí)設(shè)計(jì)面板中多了一些紅色的線條,這說(shuō)明缺少約束或者約束有沖突.

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

    接著個(gè)體TableView增加一個(gè)Prototype Cell.

    然后展開(kāi)TableView選中Table View Cell,給它設(shè)置一個(gè)重用ID.

    為了區(qū)分接下來(lái)要添加的TableView,選中當(dāng)前的TableView,給它設(shè)置一個(gè)tag,這里設(shè)置為101,再給它取一個(gè)名字.

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

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

    現(xiàn)在選中SecondTableView為它增加約束.

    此時(shí)又出現(xiàn)了紅色的線條.沒(méi)關(guān)系,有這個(gè)方法讓紅色線條消失.選中FirstTableView,按住ctrl鍵,鼠標(biāo)左鍵從FirstTableView拖出一條箭頭到SecondTableView,松開(kāi)鼠標(biāo)在彈出菜單中選擇Equal Widths.這樣做的結(jié)果是,兩個(gè)TableView具有相同的寬度.

    ok,到此為止,storyboard的設(shè)計(jì)工作完成,接下來(lái)進(jìn)入代碼階段.

代碼階段

打開(kāi)輔助視圖,為設(shè)計(jì)面板中的控件生成相應(yīng)的outlet.同時(shí)為Segmented Control綁定一個(gè)Action,它的事件類型為Value Changed,可以把Segmented Control上的items當(dāng)作獨(dú)立的button來(lái)使用.



完成后,代碼文件會(huì)類似于這樣.

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. 當(dāng)Segmented Control選擇的item改變時(shí),會(huì)觸發(fā)這個(gè)Action
    @IBAction func tabChanged(sender: AnyObject) {

    }
}

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

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

讓當(dāng)前ViewController遵循UITableViewDataSource協(xié)議,這樣就能夠給TableView提供數(shù)據(jù).類定義的頭部將會(huì)是下面的樣子.
class ViewController: UIViewController, UITableViewDataSource
這里為什么不讓ViewController遵循UITableViewDelegate協(xié)議呢.因?yàn)檫@個(gè)例子只是給TableView填充數(shù)據(jù),并不處理發(fā)生在TableView上的行為事件.
接著實(shí)現(xiàn)兩個(gè)代理方法,為T(mén)ableView填充數(shù)據(jù).把這兩個(gè)方法添加在prefersStatusBarHidden()函數(shù)的下方.

// 4. 為T(mén)ableView填充數(shù)據(jù)
    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 = "第一個(gè)TableView"
        }
        else {
            cell.textLabel!.text = "第二個(gè)TableView"
        }
        
        return cell
    }

這里利用tag來(lái)判斷是哪一個(gè)TableView,然后使用設(shè)置好的reused identifier來(lái)獲取到cell,給cell的textLabel設(shè)置簡(jiǎn)單的字符串.
在viewDidLoad()函數(shù)中,添加以下兩行代碼.這樣TableView的代理方法將會(huì)由當(dāng)前的ViewController來(lái)執(zhí)行.

firstTableView.dataSource = self
secondTableView.dataSource = self

選擇一個(gè)模擬器,運(yùn)行一下看有什么效果.



第一個(gè)TableView已經(jīng)呈現(xiàn)出來(lái)了,試著往左滑動(dòng),把第二個(gè)TableView呈現(xiàn)出來(lái).滑了幾次,發(fā)現(xiàn)不能將SecondTableView呈現(xiàn)出來(lái),為什么會(huì)這樣呢??難道SecondTableView沒(méi)有添加到ScrollView中.利用前面添加的Action來(lái)做個(gè)實(shí)驗(yàn),看是否把SecondTableView添加到了ScrollView中.
首先viewDidLoad()函數(shù)的上方,定義一個(gè)變量,用來(lái)記錄ScrollView的內(nèi)容偏移量.

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

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

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

item的下標(biāo)從0開(kāi)始.因?yàn)門(mén)ableView的寬度和屏幕的寬度相同,所以呈現(xiàn)FirstTableView時(shí)ScrollView的內(nèi)容偏移量為0,呈現(xiàn)SecondTableView時(shí)ScrollView的內(nèi)容偏移量為一個(gè)屏幕的寬度,即(self.view.frame.width).
再運(yùn)行一遍程序,當(dāng)點(diǎn)擊Second item時(shí),可以把SecondTableView呈現(xiàn)出來(lái),說(shuō)明有把SecondTableView加到ScrollView中.



到這個(gè)階段的完整代碼如下.

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. 定義一個(gè)變量來(lái)記錄scrollview的內(nèi)容偏移量
    var offset: CGFloat = 0.0 {
        
        // 當(dāng)offset的值改變后會(huì)執(zhí)行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. 當(dāng)Segmented Control選擇的item改變時(shí),會(huì)觸發(fā)這個(gè)Action
    @IBAction func tabChanged(sender: AnyObject) {
        // a. 獲取到當(dāng)前item的下標(biāo)
        let index = (sender as! UISegmentedControl).selectedSegmentIndex
        
        // b. 設(shè)置scrollview的內(nèi)容偏移量
        offset = CGFloat(index) * self.view.frame.width
    }
    
    // 3. 隱藏狀態(tài)欄
    override func prefersStatusBarHidden() -> Bool {
        return true
    }
    
    // 4. 為T(mén)ableView填充數(shù)據(jù)
    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 = "第一個(gè)TableView"
        }
        else {
            cell.textLabel!.text = "第二個(gè)TableView"
        }
        return cell
    }
}

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

// 6. 為scrollView增加滑動(dòng)手勢(shì)識(shí)別器
        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)

定義了兩個(gè)滑動(dòng)的手勢(shì)識(shí)別器,方向分別向左和向右,numberOfTouchesRequired的意思是只要單點(diǎn)觸摸就可以完成滑動(dòng)操作.
把swipe()函數(shù)添加到最后一個(gè)花括號(hào)的上方.

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

0k,代碼階段也結(jié)束了.
運(yùn)行一下程序, 左右滑動(dòng)可以呈現(xiàn)不同的TableView,選中的segmented item也會(huì)跟著改變.
圖片加載不出來(lái)的話, 這里有pdf格式的,提取碼:84e9

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贬媒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子炫狱,更是在濱河造成了極大的恐慌闻书,老刑警劉巖隆敢,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡突琳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)澡匪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)熔任,“玉大人,你說(shuō)我怎么就攤上這事唁情∫商Γ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵甸鸟,是天一觀的道長(zhǎng)惦费。 經(jīng)常有香客問(wèn)我,道長(zhǎng)哀墓,這世上最難降的妖魔是什么趁餐? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮篮绰,結(jié)果婚禮上后雷,老公的妹妹穿的比我還像新娘。我一直安慰自己吠各,他們只是感情好臀突,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著贾漏,像睡著了一般候学。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上纵散,一...
    開(kāi)封第一講書(shū)人閱讀 49,929評(píng)論 1 290
  • 那天梳码,我揣著相機(jī)與錄音,去河邊找鬼伍掀。 笑死掰茶,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蜜笤。 我是一名探鬼主播濒蒋,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼把兔!你這毒婦竟也來(lái)了沪伙?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤县好,失蹤者是張志新(化名)和其女友劉穎围橡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體聘惦,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡某饰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年儒恋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黔漂。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诫尽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出炬守,到底是詐尸還是另有隱情牧嫉,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布减途,位于F島的核電站酣藻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鳍置。R本人自食惡果不足惜辽剧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望税产。 院中可真熱鬧怕轿,春花似錦、人聲如沸辟拷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)衫冻。三九已至诀紊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間隅俘,已是汗流浹背邻奠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留为居,地道東北人惕澎。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像颜骤,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捣卤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容