Section、row的個數不定的UITableView實現方式最佳實踐

先解釋下題目,好比下面這個設置頁面,裏面的內容會根據用戶身份、權限等等看到不一樣的可設置內容:3d

  • 好比左邊有3個section;右邊有4個
  • 左邊section[0]中有4個row;右邊section[0]中有2個row
  • 左邊section[0] row[0]可點擊;右邊則不可點擊
  • 等等

咱們先假設最簡單的狀況,形成左右兩邊差別的緣由徹底就是因爲一個變量的值的不一樣致使,isMyHome,若是爲YES,則最終看到左邊的效果,若是爲NO,則最終看到右邊的效果。代理

問題來了,你會如何實現UITableView的各類delegate?code

錯誤示範,一種很醜的實現方式

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if (self.isMyHome) {
        return 3;
    } else {
        return 4;
    }
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (self.isMyHome) { // 有3個section
        switch (section) {
            case 0:
                return 4;
                break;
            case 1:
                return 1;
                break;
            case 2:
                return 2;
                break;
            default:
                break;
        }
    } else {
        switch (section) {
            case 0:
                return 2;
                break;
            case 1:
                return 1;
                break;
            case 2:
                return 1;
                break;
            case 3:
                return 1;
                break;
            default:
                break;
        }
    }
    return 0;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (self.isMyHome) {
        if (indexPath.section == 2 && indexPath.row == 0) { // 有一個row稍微有點高
            return 70;
        } else {
            return 40;
        }
    } else {
        return 40;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = ni;
    // ...真的不想寫了快吐了,這才一個變量的區別
    return cell;
}

以上的寫法有兩個大問題:blog

  1. 任什麼時候候都要考慮isMyHome的值,寫一堆if、else、switch。(一個row是否要顯示,row的index是多少,row長什麼樣都是變量,都要考慮)
  2. 使用0,1,2,3等數字,沒有含義,沒有使用枚舉,難以維護,增刪一行都要改所有,還容易出bug。

這才一個變量啊,試想實際項目中,每每不少變量綜合決定了哪一個row顯示、那個row不顯示、row長什麼樣。想一想下,若是有一天產品經理說,去掉「寶寶信息」這行,我以爲你就要瘋了,要把index所有都減一,每一個代理都要檢查一遍是否對得上index。ci

因此,這兩個問題,致使的後果:難實現、容易出bug、不易維護。產品

最佳實現

既然上面的實現這麼很差,該怎麼實現呢?其實就是逐一解決上面提到的兩個問題。it

對於1,其實形成問題的本質緣由是:在任什麼時候候,把一個row應該顯示與否、以及長什麼樣子、row對應的index是什麼, 這些問題都融合在一塊兒了,將問題複雜程度一下提高了不少。對於2,都使用枚舉就行了,避免
這裏提出解決辦法:io

  1. 固定section的個數、每一個section中row的個數,都取全部條件下,最多的那個值。(numberOfSectionsInTableView、numberOfRowsInSection只控制個數問題)
  2. heightForRowAtIndexPath中控制row的顯示與否,若是不顯示,只須要高度返回0就行了
  3. cellForRowAtIndexPath裏,因爲section、row的index都是固定不變的,只須要關心cell的內容就行了。
  4. 使用枚舉

這樣,「section、row的個數(index)」、「section、row是否顯示」、「row長什麼樣」,這三個問題就分散到了4個delegate中:table

  • numberOfSectionsInTableView、numberOfRowsInSection只解決「section、row的個數(index)」的問題;
  • heightForRowAtIndexPath只解決「section、row是否顯示」的問題
  • cellForRowAtIndexPath只解決「row長什麼樣」的問題

代碼長這樣:變量

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 4;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    switch (section) {
        case SectionOne:
            return 4;
            break;
        case SectionTwo:
            return 1;
            break;
        case SectionThree:
            return 2;
            break;
        case SectionFour:
            return 1;
            break;
            
        default:
            break;
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.section == 0) {
        switch (indexPath.row) {
            case SectionOneRowOne:
                return 40
                break;
            case SectionOneRowTwo:
                return self.isMyHome ? 40 : 0;
                break;
            case SectionOneRowThree:
                return self.isMyHome ? 40 : 0;
                break;
            case SectionOneRowFour:
                return 40
                break;
                
            default:
                break;
        }
    } else if (indexPath.section == 1) {
        return 40;
    } else if (indexPath.section == 2) {
        switch (indexPath.row) {
            case SectionThreeRowOne:
                return self.isMyHome ? 70 : 0;
                break;
            case SectionThreeRowTwo:
                return 40;
                break;
            default:
                break;
        }
    } else {
        return self.isMyHome ? 0 : 40;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    // 對於每一個cell,配置內容就行了,index都是固定的
}

若是產品經理說,刪除「寶寶信息」這行吧,那麼咱們只要把heightForRowAtIndexPath,相應高度改成0就行了,以後產品經理反悔還能夠直接改回來,就算想徹底刪了,也很省事,不容易出bug。

總結

核心思想,其實就是,UITableView的幾個delegate,分別只解決一個問題,不要把問題都揉在一塊兒,讓代碼變得複雜

其餘問題

假如要去掉一整個section怎麼辦,好比產品經理說,不要「我在小家的稱呼」這行了。

固然,沒問題,咱們直接把heightForRowAtIndexPath裏這行,改成0就行了嘛!

等等,雖然這行沒了,可是前兩個section之間的間隙,有可能會變大,由於只是設置了height爲0而已,seciton還在嘛。這種狀況怎麼辦?
不用擔憂,只要設置section的間隙,使用相似這種方式去設置,響應的改變section header的值,就行了~
其實,這種設置section的間隙的方式,也是咱們常用的嘛,基本都不太用系統默認的間隙。

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return section == 0 ? 0 : 8;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section == 0) {
        return [UIView new];
    }
    UIView *sectionHeader = [[UIView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 8)];
    sectionHeader.backgroundColor = [UIColor clearColor];
    return sectionHeader;
}
相關文章
相關標籤/搜索