1. 程式人生 > >關於在storyboard中使用靜態cell的注意事項

關於在storyboard中使用靜態cell的注意事項

關於在storyboard中使用靜態TableViewCell的可變高度的使用技巧

起因:storyboard使用之前,建立tableView檢視,通常是採用程式碼控制資料來源,通過資料來源資料的長度來決定tableViewcell的個數,而這樣做的好處還有就是可以通過將已經在介面中展示的cell放入快取池中,以供後續資料展示再從快取池中取出進行復用。這樣做的好處是為了防止資料過大時建立大量的cell浪費不必要的空間。顯而易見,tableView就是為了進行批量資料的展示。
然而,在現實開發中,會出現一種需求:展示的資料長度是確定的,而且需要向tableView一樣實現檢視上下滾動,單個cell

檢視可點選響應。這種情況下,繼續使用原來的程式碼資料來源控制一樣可以實現,這時的資料來源個數是確定的。即便如此,你也需要考慮處理cell滾動時發生的重用所帶來的影響。而且當資料來源確定時,你的產品經理絕對不甘於像平常一樣每條資料都展示為同一個尺寸內容。而是會盡可能地在每個cell中加入豐富的控制元件,時間相應來是有限的tableView實現最為複雜的使用者互動事件。此時,你會在自己的資料來源拼命地書寫if語句來保證檢視的正確顯示,又要避免發生未知的cell重用問題。
這樣做是可行的,但是在主要時間將大量花費在處理有限個數cell上的邏輯處理,而並非我們所要實現的主要業務。
所以,在這種情況下,我們會考慮把這些重複而且無用的邏輯處理交給蘋果自己搞定(當然,主要目的是為了偷懶^_^)
static cell
,這是蘋果為我們提供的解決方案。目前僅限於在storyboard中使用。

static cell的用法非常簡單,這裡不作為重點贅述,請大家自行學習。
現在給大家這樣一個場景,在你用static cell搭建好介面,然後輕鬆加愉快的拖拖控制元件,完成相關業務功能。
上面老闆開始驗收專案,對產品說你的介面不夠詳細,再改改。
產品開始提需求,說我們的cell內容太少,需要在點選時展開詳情。
而恰好你用靜態單元cell偷了個懶,現在要為了一個cell重新用動態cell寫一遍?
別鬧了,明天還要和UI妹子去爬香山呢,絕壁不當加班狗。
所以,我們開始探索靜態cell的高度改變之旅。

方案一:
既然我們可以將靜態cell當做一個控制元件拖入控制器做屬性。何不在程式碼中修改作為屬性的靜態cell的高度呢?

        self.fuJianCell.height = 100;       
        [self.fuJianCell layoutIfNeeded];
        [self.tableView reloadData];

然並卵,這些方法對非cell的控制元件來說重新整理高度足矣,然而tableView的高度始終是由代理來控制的,所以這樣修改是沒用的。
既然這樣,我們就從高度代理入手。

方案二:
通過代理入手,將每個cell的在storyBoard的設定高度用程式碼寫到一個數組中,並通過代理返回。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 變高行數
    NSInteger mutableHeightRow = 1;
    // 如果不展開
    if(!isOpen){
        self.heights[mutableHeightRow] = @(原始高度);
        return [self.heights[indexPath.row] integerValue];
    } else {
        self.heights[mutableHeightRow] = @(展開高度);
        return [self.heights[indexPath.row] integerValue];
    }
}

問題解決,但是違背了我們的初衷,說好的交給蘋果自己算呢,為毛要手動將高度存在陣列中?

方案三:
交給tableView的父類方法返回我們在storyboard中預設的高度,然後單獨處理變高的cell高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 變高行數
    NSInteger mutableHeightRow = 1;
    if (indexPath.row == mutableHeightRow) {
        if (!isOpen) {
            // 假設改行原來高度為200
            return 80;
        } else {
            return [super tableView:tableView heightForRowAtIndexPath:indexPath];
        }
    } else {
        /** 返回靜態單元格故事板中的高度 */
        return [super tableView:tableView heightForRowAtIndexPath:indexPath];
    }
}

完美~

// 注意別忘了,在修改展開狀態的時候重新整理表格
    isOpen = YES;
    [self.tableView reloadData];

其實,這樣處理靜態cell的方式不光可以處理可變高度,還可以用在資料來源的section個數或者每個section的row的個數上,再或者指定讓某個位置的cell使用動態cell其他使用靜態cell,讓我們的靜態cell比動態cell更好用。其方法都是通過super關鍵字呼叫父類方法返回storyboard中儲存的的相關資料。

至於原理,暫時還不清楚,推測使用了執行時動態建立一個支援靜態cell的tableView的子類,我們實際使用的是這個新的tableView類的例項,或者使用類簇,利用私有子類進行了相關的靜態cell的邏輯處理。

總之,這讓我們省去了很多處理邏輯的程式碼。