iOS初級開發學習筆記:一個頁面中自動計算cell的高度來自適應tableView的高度

項目中有一個頁面爲活動詳情頁,其中活動的相關內容放置於一個底色爲白色的view中,其餘的背景色爲灰色。效果完成圖以下數組

由於內容分爲活動時間、金額、規則等且有橫線隔開,因此決定用 tableview 來畫,建立一個 cell 文件添加內容,再建立一個 controller 在內建立 tableview 承載便可。bash

內容因爲分類不一樣放置於各個 cell 中。然而其中文字內容長度均不一樣且在後續使用中一定會改變。 cell 的高度根據內容自適應由app

//row高自適應
_tableView.rowHeight = UITableViewAutomaticDimension;
//給一個預估值,當計算不出時會默認使用此高度
_tableView.estimatedRowHeight = 100;
複製代碼

便可設置。佈局

而 tableview 的高度要根據各 cell 高度來計算累加該怎麼作呢?

先這樣想:計算每個 cell 的高度,再把它們各自高度的值傳至 controller 中進行累加。ui

首先須要傳值,選擇用 ReactiveObjc(即RAC) 來進行傳值:atom

在 cell.h 中聲明 subject :spa

@property (nonatomic, strong) RACSubject *subject;
複製代碼

cell.m 中懶加載建立:代理

- (RACSubject *)subject{
    if (!_subject) {
        _subject = [RACSubject subject];
    }
    return _subject;
}
複製代碼

在建立 cell 的代理中的語句code

ABLaborActivityDetailViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
複製代碼

一開始,在 cell.m 中的 setLayout 佈局方法中,是先走一遍及局,建立控件的,在執行至 cell.index = indexPath.row; 時,纔會走 setIndex 方法,給控件內容賦值。cdn

因此要確認什麼時候開始傳值,咱們要聲明一個全局變量

BOOL _isLayout;//狀態開關
複製代碼

並在佈局方法 - (void)setLayout 中一開始令初始狀態爲 NO

_isLayout = NO;
複製代碼

setIndex 賦值方法中:

- (void)setIndex:(NSInteger)index{
    self.titleLabel.text = self.dataArray[index][@"title"];
    self.detailLabel.text = self.dataArray[index][@"detail"];
    //經過 index 和數組給 cell 內容賦值時,讓開關爲 YES ,走幾回由咱們建立的數組決定,每一次都會走 layoutIfNeeded 方法。
    _isLayout = YES;
    //調用 layoutSubviews 方法
    [self layoutIfNeeded];
}

複製代碼

也就是走完一次 setLayout 建立空控件後,讓 _isLayout = YES;

此時纔開始傳值,此方法添加在 setLayout 方法末尾:

- (void)layoutSubviews{
    [super layoutSubviews];
    //每次信號爲 YES ,都會經過 RAC 傳出 cell 的高度 self.size.height 。
    if (_isLayout == YES) {
        [self.subject sendNext:@(self.size.height)];
        //打印 cell高檢查
        NSLog(@"CELL高=%f",self.size.height);
    }
    
複製代碼

執行結果打印 cell 高以下,前10行,均爲計算空控件賦值前的初始高度(44)-> 獲得內容後的高度,循環5次(由於有5個 cell ),後5行即各cell最終高度。

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=81.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=44.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=96.500000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=50.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=81.000000

function:-[ABLaborActivityDetailViewCell layoutSubviews] line:82 content:CELL高=96.500000
複製代碼

這樣在 cell 內傳值結束, cell 內代碼也結束啦

到對應的 controller 中:

須要建立全局變量接收傳過來的 cell 高:

{
    CGFloat _tableViewHeight;//接收cell的高度
    BOOL _isEnd;//刷新開關
}

複製代碼

這裏有個 BOOL 變量,由於在接收值刷新 tableview 的時候,會出現死循環,爲了解決死循環,需給一個開關進行判斷什麼時候刷新中止。

在 viewDidLoad 中給兩個全局變量以初始狀態:

_tableViewHeight = 0;//給初始高度
    _isEnd = NO;//給初始狀態
複製代碼

在 cell 內容代理中:

weakifyySelf;
    [cell.subject subscribeNext:^(NSNumber *x) {
        stronggSelf;
        //接收cell值並累加
        _tableViewHeight = _tableViewHeight + [x floatValue];
        //在進行到第5行時,而且開關處於 NO 狀態,則執行開關切換爲YES,防止再次刷新;給 tableview 範圍,
        並刷新數據,令其顯示正確範圍,高度計算完畢需按實際狀況進行調整,這裏 +50 使顯示徹底
        if (indexPath.row == 4 && _isEnd == NO) {
            _isEnd = YES;
            self.tableView.size = CGSizeMake(SCREEN_WIDTH - 30, _tableViewHeight+50);
            [self.tableView reloadData];
        }
    }];
複製代碼

這裏再貼一遍最終效果:

一些細節:

活動詳情內容,須要給一個最大寬度,考慮適配,應該計算,而不是給肯定值,這裏例子爲(左側例如「挑戰時間」這些title我是給了控件寬度的,計算時要減去):

//自動換行
_detailLabel.numberOfLines = 0;
//3一、33爲左右邊距,67爲左側title長度
_detailLabel.preferredMaxLayoutWidth = SCREEN_WIDTH - 31-33 - 67;
複製代碼

做者介紹

  • 李鴻:廣州蘆葦科技 APP 團隊 iOS 開發工程師

內推信息

  • 咱們正在招募小夥伴,有興趣的小夥伴能夠把簡歷發到 app@talkmoney.cn,備註:來自掘金社區
  • 詳情能夠戳這裏--> 廣州蘆葦信息科技
相關文章
相關標籤/搜索