UITableView 及UITableViewCell 簡述

做爲在開發中最經常使用的一個控件,UITableView也是在整個UIKit中比較複雜的一個,咱們須要記的東西也特別多.另外蘋果官方爲咱們提供了UITableViewController這個類,可是在這裏咱們不使用它.而是在UIViewController上面添加一個UITableView.數組

UITableView

UITableView繼承於UIScrollView,當須要展現的數據量不少的時候,它是能夠滾動顯示的.bash

UITableView

表視圖的每一行都是由單元格(UITableViewCell)表示的.當咱們要對數據分組顯示時,蘋果爲咱們提供了兩種基本樣式的顯示,一種是分組樣式,一種則爲簡單樣式.ide

樣式

建立UITableView

咱們初始化一個UITableView,並指定樣式,而後進行其相關屬性的設置,最後將他添加到控制器上.動畫

// 1.建立tableView(表視圖)並初始化,初始化的時候給一個樣式
    UITableView *tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped];
    
    // 2.設置屬性
    // 設置分割線的顏色
    tableView.separatorColor = [UIColor redColor];
    // 設置分割線的風格
    tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
    // 設置行高
    tableView.rowHeight = 100;
    
    // 設置tableView的tableHeaderView
    UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 414, 200)];
    headerView.backgroundColor = [UIColor cyanColor];
    tableView.tableHeaderView = headerView;
    
    // 設置tableView的tableFooterView(取消下面多餘的線)
    UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
    footerView.backgroundColor = [UIColor magentaColor];
    tableView.tableFooterView = footerView;
    
    // 設置索引條
    
    tableView.sectionIndexColor = [UIColor blackColor];
    // 背景顏色
    tableView.sectionIndexBackgroundColor = [UIColor clearColor];
    //
    tableView.sectionIndexTrackingBackgroundColor = [UIColor lightGrayColor];
    
    
    // 3.添加到視圖
    [self.view addSubview:tableView];
    
複製代碼

在上面的代碼中,咱們對UITableView的分割線和行高,一塊兒頭尾視圖,索引條這幾個屬性進行了相關設置,對於其餘的屬性,讀者能夠本身根據興趣嘗試設置.ui

關於UITableViewCell的相關

在UITableView中用於展現數據的主要就是UITableViewCell.在這裏首相我想先說一下關於UITableViewCell的重用.spa

UITableViewCell的重用

若是咱們想利用UITableView展現幾條數據的話,咱們能夠依次建立這些數量的行來展現這些數據,可是咱們若是有10000行甚至更多的數據要用來向用戶展現呢?若是反覆建立是十分消耗內存的.代理

這樣咱們就天然的想到,爲何要建立這麼屢次cell呢?咱們爲何不將建立好的cell保存起來,放在一個隊列中重用呢?這就是UITableViewCell的重用機制.當咱們有10000條數據須要展現的時候,咱們使用這個機制建立的行可能僅須要10個,這樣就大大節約了內存.code

UITableViewCell的建立

咱們能夠從官方的API中看到UITableViewCell的初始化方法.cdn

![UITableViewCell的初始化方法]://upload-images.jianshu.io/upload_images/1230517-db6401da06482690.png)對象

在建立Cell的時候一樣須要指定一個樣式,而且設置一個標識.關於樣式蘋果給定了四個樣式

Cell樣式

讀者能夠一一試驗,着這裏就不作詳細的講解.

if (!cell) {
        // 若重用池裏面沒有,則去建立identifier標識符的cell
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
    }
複製代碼

實際上,上述的建立UITableViewCell的方法是在iOS6以前的老方法.

在iOS6以後咱們只須要註冊在重用池中註冊一下cell的重用標識符.在註冊cell以前咱們必須爲cell設置重用標識符,這個標識符必須惟一.咱們一般聲明爲靜態字符串,咱們不須要管理字符串的內存,也不須要對其進行釋放.

// 聲明重用標識符
static NSString *identifier = @"cellReuse";
複製代碼
// 註冊(iOS6 以後的寫法)
    [tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier];
複製代碼

而後在UITableViewDataSource數據源方法中建立就能夠了

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    // 先去重用池裏面取帶有identifier重用標識符的cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];    
    return cell;
}
複製代碼

NSIndexPath

NSIndexPath表明UITableView的索引.因爲咱們建立的cell是重用的,這樣一來咱們便無法精確的肯定這個行.出於此,系統爲咱們提供了一個標示行的類,就是NSIndexPath

NSIndexPath的經常使用屬性有:

row表示分區中的行的索引,section標示分區的索引.經過這兩個屬性咱們就能夠找到想要的行.

關於自定義cell

關於UITableViewCell咱們是能夠根據本身的須要自定義的,咱們只須要從新建立一個類繼承自UITableViewCell,在其中設置成須要的樣式.而後在註冊和建立的時候使用自定義的cell就能夠了,在這裏咱們假設咱們建立一個MyTableViewCell,而且設置了重用標識符,那麼註冊和建立的方式以下.

註冊
[self.tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:identifier];
複製代碼
建立
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
複製代碼

UITableViewDelegate和UITableViewDataSource

上面是對UITableView的總體結構介紹,若是咱們要建立表視圖展現數據,咱們必需要爲表視圖設置代理和數據源,也就是UITableViewDelegate和UITableViewDataSource

先看數據源代理,數據源顧名思義,就是爲表視圖提供相關的數據.

數據源中必須實現的方法

咱們看到API中有兩個必需要實現的方法

//分區的個數,也就設置這個表分紅幾組(section)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;

//建立或者重用cell的代理方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
複製代碼

另外咱們能夠對其每一個分區的行數(row)進行設置,還能夠設置其頭尾(titleForHeaderInSection和titleForFooterInSection).

相對這些我跟想跟你們交流的是一些有趣的方法

編輯UITableView

使頁面處於可編輯狀態

// 第一步: 使頁面處於可編輯狀態
- (void)edit:(UINavigationController *)sender{
    
    // 設置當前頁面能夠被編輯
    // 當點擊編輯的時候,頁面應該處於可編輯狀態,而且按鈕文字變成"完成"
    if ([sender.title isEqualToString:@"編輯"]) {
        sender.title = @"完成";
        [_tableView setEditing:YES animated:YES];
        
    }else{
        // 當點擊完成時,應該讓當前頁面處於不可編輯狀態,而且按鈕文字顯示爲"編輯"
        sender.title = @"編輯";
        [_tableView setEditing:NO animated:YES];
        
    }
    
}
複製代碼

指定哪些行能夠被編輯

// 指定哪些行能夠被編輯
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
    
    if (indexPath.section == 2) {
        return NO;
    }
    
        return YES;
    
}
複製代碼

根據路徑指定編輯的樣式

// 根據路徑指定編輯的樣式
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    if (indexPath.section == 5) {
        return UITableViewCellEditingStyleInsert;
    }
        return UITableViewCellEditingStyleDelete;
}
複製代碼

根據編輯風格完成編輯(先操做數據,在更新UI)

// 根據編輯風格完成編輯(先操做數據,在更新UI)
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
    // 刪除
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        
        // 找到對應得分組
        NSMutableArray *array = _dataDictionary[_dataArray[indexPath.section]];
        // 噹噹前分組只有一我的的時候,刪除元素以後,對應的分組也應該被刪掉
        if (array.count == 1) {
            // 刪除大字典裏面的該分組
            [_dataDictionary removeObjectForKey:_dataArray[indexPath.section]];
            // 刪除掉數組裏面對應的key
            [_dataArray removeObjectAtIndex:indexPath.section];
            // 刪除UI
            NSIndexSet *set = [NSIndexSet indexSetWithIndex:indexPath.section];
            
            [tableView deleteSections:set withRowAnimation:UITableViewRowAnimationFade];
            
            
        }else{
            
            // 刪除數據
            [array removeObjectAtIndex:indexPath.row];
            // 刪除對應的cell  更新UI
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
            

        }
        
    }else{
        // 增長
        NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"悟空",@"name",@"男",@"age",@"八戒",@"hobby",@"18833336666",@"phoneNumber",12,@"age",@"八戒.png",@"picture", nil];
        // 找到對應的分組
        NSMutableArray *array = _dataDictionary[_dataArray[indexPath.section]];
        // 添加元素
        [array insertObject:dic atIndex:indexPath.row+1];
        // 增長 更新UI
        // <1 定義一個新路徑
        NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
        [_tableView insertRowsAtIndexPaths:@[newPath] withRowAnimation:UITableViewRowAnimationTop];
    }
    
}
複製代碼

移動UITableViewCell

使頁面處於可編輯狀態

// 第一步 使頁面處於可編輯狀態
-(void)setEditing:(BOOL)editing animated:(BOOL)animated{
    
    [super setEditing:editing animated:animated];
    
    [_tableView setEditing:editing animated:animated];
    
    self.navigationItem.rightBarButtonItem.title = editing? @"完成":@"編輯";
}
複製代碼

指定tableView哪些行能夠被移動

// 第二步 指定tableView哪些行能夠被移動
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{
    return YES;
}
複製代碼

移動完成

// 第三步 移動完成
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
    // 獲取移動的數據
    NSMutableArray *array = _dataDictionary[_dataArray[sourceIndexPath.section]];
    // 獲取移動的對象
    NSDictionary *dic = [array objectAtIndex:sourceIndexPath.row];
    // 先刪除
    [array removeObjectAtIndex:sourceIndexPath.row];
    // 再添加
    [array insertObject:dic atIndex:destinationIndexPath.row];
}
複製代碼

檢測跨區移動

// 檢測跨區移動
-(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath{
    // 若是就在一個分區,則容許任意移動
    if (sourceIndexPath.section == proposedDestinationIndexPath.section) {
        return proposedDestinationIndexPath;
    }
    // 不然原路滾回去
    return sourceIndexPath;
}
複製代碼

經常使用的方法還有

// 快速索引
- (nullable NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
複製代碼

UITableViewDelegate中經常使用方法

// 設置行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
複製代碼
// 設置分區的header高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
複製代碼
// 設置分區的footer高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
複製代碼
// 設置分區headerView的視圖(設置以後,與titleForHeader方法不共存且設置的高度沒有用,想要肯定,headerView的高度,必須重寫heightForHeaderInSection方法)
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
複製代碼
// 設置分區footerView的視圖
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
複製代碼
// 點擊觸發事件
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
複製代碼

刷新UITableView

試想一下,當咱們建立UITableView完成以後,咱們向其中添加或者更改刪除了一條數據,咱們想讓最新的數據呈現出來該怎麼辦呢?很天然的咱們就想到了從新加載一遍,也就是刷新了.

關於刷新數據系統提供給咱們三種方法.

// 刷新整個表格
-(void)reloadData;
複製代碼
// 刷新某些section,animation表示刷新時使用的動畫
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
複製代碼
// 刷新某些row
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
複製代碼

UITableViewController

上面說了這麼多,咱們發現建立一個表視圖真的好麻煩,要設置代理和數據源,還有那麼多的方法.那麼有沒有一種更好的方法來替代這些方法呢?答案固然是確定的.爲了提升開發效率,Apple將UITableView和UIViewController結合,產生了UITableViewController.

使用UITableViewController,咱們只須要根據須要使用其方法進行配置就行了.若是搞懂了UITableView,那麼使用UITableViewController就駕輕就熟了,其實這兩個一模一樣,在此就不贅述了.

總結

以上就是UITableView和UITableViewCell的簡單介紹,若是有疑問或者錯誤,歡迎指正交流,我將不勝感激.轉載請保留連接.

相關文章
相關標籤/搜索