tableView

方式一:解偶的方式創(chuàng)建TableView

#import "TableViewController.h"

#import "TestTableView.h"

@interface TableViewController ()

@property(nonatomic , strong) TestTableView * tableView;

@end

@implementation TableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColor.whiteColor;
    [self loadDataisFirst];
}

#pragma mark - 交互

- (void)detailClick:(NSIndexPath *)indexPath
{
    NSLog(@"%ld-----------%ld",(long)indexPath.section,(long)indexPath.row);
}

#pragma mark - 網(wǎng)絡(luò)

- (void)loadDataisFirst
{
    self.tableView.array = @[@"-1-",@"-2-",@"3-3",@"5-5",@"6-6"];
}

#pragma mark - 懶加載

-(UITableView *)tableView
{
    if (_tableView == nil) {
        _tableView = [[TestTableView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64) style:UITableViewStyleGrouped];
        _tableView.backgroundColor = UIColor.grayColor;
        [self.view addSubview:_tableView];
        _tableView.itemClick = ^(NSIndexPath * _Nonnull indexPath) {
            [self detailClick:indexPath];
        };
    }
    return _tableView;
}

TestTableView

@interface TestTableView : UITableView

@property (nonatomic, strong) NSArray *array;

@property (nonatomic, copy) void (^itemClick)(NSIndexPath *indexPath);

@end
#import "TestTableView.h"

#import "TestTableViewCell.h"
#import "TestTableViewHeaderFooterView.h"

@interface TestTableView () <UITableViewDelegate, UITableViewDataSource>

@end

@implementation TestTableView

- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
    self = [super initWithFrame:frame style:style];
    if (self) {
        self.separatorStyle = UITableViewCellSeparatorStyleNone;
        self.autoresizingMask = UIViewAutoresizingFlexibleHeight;
        //
        self.delegate = self;
        self.dataSource = self;
        [self registerClass:[TestTableViewCell class] forCellReuseIdentifier:NSStringFromClass(TestTableViewCell.class)];
        [self registerClass:[TestTableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:NSStringFromClass(TestTableViewHeaderFooterView.class)];
    }
    return self;
}

#pragma mark - 交互


#pragma mark - delegate

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return  self.array.count;
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return self.array.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(TestTableViewCell.class) forIndexPath:indexPath];
    cell.reasonLabel.text = [NSString stringWithFormat:@"我是第%ld個(gè)cell",(long)indexPath.row];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    if (self.itemClick) {
        self.itemClick(indexPath);
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 100;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return 30;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return 10;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    TestTableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:NSStringFromClass(TestTableViewHeaderFooterView.class)];
    return headerView;
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    UIView *footerView = [[UIView alloc] init];
    footerView.backgroundColor =  UIColor.blueColor;
    return footerView;
}

#pragma mark - setter

- (void)setArray:(NSArray *)array
{
    _array = array;
    [self reloadData];
}


方式二:保守的創(chuàng)建方式TableView

estimated:預(yù)估

//高度自適應(yīng)
self.tableView.estimatedRowHeight = 88;
self.tableView.rowHeight = UITableViewAutomaticDimension;
//cell的細(xì)節(jié)
[self.contentView addSubview:self.retryBtn];

//在iOS 11上運(yùn)行tableView向下偏移64px或者20px西雀,因?yàn)閕OS 11廢棄了automaticallyAdjustsScrollViewInsets,
//而是給UIScrollView增加了contentInsetAdjustmentBehavior屬性。避免這個(gè)坑的方法是要判斷
if (@available(iOS 11.0, *)) {
_tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}else {
self.automaticallyAdjustsScrollViewInsets = NO;
}

//tableView的sectionHeader、sectionFooter高度與設(shè)置不符觅廓,因?yàn)閠ableView的estimatedRowHeight觉啊、
//estimatedSectionHeaderHeight、 estimatedSectionFooterHeight三個(gè)高度估算屬性由默認(rèn)的0變成了
//UITableViewAutomaticDimension零聚。最簡單的方法就是直接設(shè)置為0榨了。
_tableView.estimatedSectionHeaderHeight = 0;
_tableView.estimatedSectionFooterHeight = 0;
_tableView.estimatedRowHeight = 0;

TableViewController.h

#import "TableViewController.h"

#import "TestTableViewCell.h"
#import "TestTableViewHeaderFooterView.h"

@interface TableViewController ()<UITableViewDelegate , UITableViewDataSource>

@property(nonatomic , strong) UITableView * tableView;

@end

@implementation TableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = UIColor.whiteColor;
    [self.view addSubview:self.tableView];
}

#pragma mark - UITableViewDataSource

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

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(TestTableViewCell.class) forIndexPath:indexPath];
    cell.reasonLabel.text = [NSString stringWithFormat:@"我是第%ld個(gè)cell",(long)indexPath.row];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 100;
}

#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
    return 30;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
    return 10;
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    TestTableViewHeaderFooterView *headerView = [tableView dequeueReusableHeaderFooterViewWithIdentifier:NSStringFromClass(TestTableViewHeaderFooterView.class)];
    return headerView;
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    UIView *footerView = [[UIView alloc] init];
    footerView.backgroundColor =  UIColor.blueColor;
    return footerView;
}

#pragma mark - 懶加載

-(UITableView *)tableView
{
    if (_tableView == nil) {
        _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, self.view.frame.size.height - 64) style:UITableViewStyleGrouped];
//        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        _tableView.delegate = self;
        _tableView.dataSource = self;
        [_tableView registerClass:[TestTableViewCell class] forCellReuseIdentifier:NSStringFromClass(TestTableViewCell.class)];
        [_tableView registerClass:[TestTableViewHeaderFooterView class] forHeaderFooterViewReuseIdentifier:NSStringFromClass(TestTableViewHeaderFooterView.class)];
        _tableView.backgroundColor = UIColor.grayColor;
        [self.view addSubview:_tableView];
    }
    return _tableView;
}

@end

TestTableViewCell

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface TestTableViewCell : UITableViewCell

@property(nonatomic,strong)UILabel *reasonLabel;

@end

NS_ASSUME_NONNULL_END
#import "TestTableViewCell.h"

@implementation TestTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
//        self.selectionStyle = UITableViewCellSelectionStyleNone;
        [self setUI];
        [self layout];
    }
    return self;
}

- (void)setUI{
    NSLog(@"---");
    [self.contentView addSubview:self.reasonLabel];
}

- (void)layout{
    self.reasonLabel.frame = CGRectMake(0, 0, 300, 100);
}

#pragma mark - 懶加載

- (UILabel *)reasonLabel{
    if (!_reasonLabel) {
        _reasonLabel = [[UILabel alloc]init];
        _reasonLabel.text = @"cell";
    }
    return _reasonLabel;
}

@end

TestTableViewHeaderFooterView

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface TestTableViewHeaderFooterView : UITableViewHeaderFooterView

@property(nonatomic,strong)UILabel *reasonLabel;

@end

NS_ASSUME_NONNULL_END
#import "TestTableViewHeaderFooterView.h"

@implementation TestTableViewHeaderFooterView

- (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier {
    
    self = [super initWithReuseIdentifier:reuseIdentifier];
    if (self) {
        [self setUI];
        [self layout];
        self.contentView.backgroundColor = UIColor.redColor;
    }
    return self;
}

- (void)setUI{
    NSLog(@"+++");
    [self.contentView addSubview:self.reasonLabel];
}

- (void)layout{
    self.reasonLabel.frame = CGRectMake(0, 0, 200, 30);
}

#pragma mark - 懶加載

- (UILabel *)reasonLabel{
    if (!_reasonLabel) {
        _reasonLabel = [[UILabel alloc]init];
        _reasonLabel.text = @"TableViewHeaderFooterView";
    }
    return _reasonLabel;
}

@end


用xib加約束和用masonry加代碼約束都是的的cell自適應(yīng)高度的使用方法

加好約束后煎谍,然后告訴tableView自己去適應(yīng)高度就可以了。有兩種寫法:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 100;
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 100;
}

這個(gè)的意思就是告訴tableView龙屉,你需要自己適應(yīng)高度呐粘,我不給你算啦哈哈哈。但是我們需要告訴它一個(gè)大概高度转捕,例如上面的100作岖,理論上這個(gè)是可以隨便寫的,并不影響顯示結(jié)果瓜富,但是越接近真實(shí)高度越好鳍咱。
其實(shí)section的header和footer也是可以自動(dòng)適應(yīng)的降盹,對應(yīng)的方法有

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section;

點(diǎn)擊狀態(tài)欄就有幾率不能精確滾動(dòng)到頂部了(不太算bug的bug)

如果我們用了自動(dòng)計(jì)算高度的方法与柑,又調(diào)用了tableView的reloadData方法(例如我們的數(shù)據(jù)有分頁的時(shí)候谤辜,加載完下一頁的數(shù)據(jù)后會(huì)去刷新tableView)。這時(shí)候就會(huì)出現(xiàn)問題价捧,點(diǎn)擊狀態(tài)欄就有幾率不能精確滾動(dòng)到頂部了丑念。

@property (nonatomic, strong) NSMutableDictionary *heightAtIndexPath;//緩存高度所用字典

-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSNumber *height = [self.heightAtIndexPath objectForKey:indexPath];
    if(height)
    {
        return height.floatValue;
    }
    else
    {
        return 100;
    }
}

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSNumber *height = @(cell.frame.size.height);
    [self.heightAtIndexPath setObject:height forKey:indexPath];
}

解釋一下,就是用一個(gè)字典做容器结蟋,在cell將要顯示的時(shí)候在字典中保存這行cell的高度脯倚。然后在調(diào)用estimatedHeightForRowAtIndexPath方法時(shí),先去字典查看有沒有緩存高度嵌屎,有就返回推正,沒有就返回一個(gè)大概高度。

常規(guī)的cell緩存高度

因?yàn)楫?dāng)tableView滾動(dòng)時(shí)會(huì)不停的回調(diào)- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;這個(gè)代理方法宝惰,當(dāng)cell的高度需自適應(yīng)內(nèi)容時(shí)植榕,就意味著每次回調(diào)這個(gè)方法時(shí)都要計(jì)算高度,而計(jì)算是要花時(shí)間了尼夺,在用戶體驗(yàn)上的體現(xiàn)就是卡頓尊残。為了避免重復(fù)且無意義的計(jì)算cell高度,緩存高度就顯得尤為重要了淤堵。

/** 緩存cell高度的數(shù)組 */
@property (nonatomic,strong) NSMutableArray *heightArray;

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    
    CGFloat height;
    
    if (self.heightArray.count > indexPath.row) {
        // 如果有緩存的高度寝衫,取出緩存高度
        height = [self.heightArray[indexPath.row] floatValue];;
    }else{
        // 無緩存高度,計(jì)算高度拐邪,并加入數(shù)組
        
        // 高度根據(jù)評論內(nèi)容多少自適應(yīng)
        CQGoodsCommentModel *model = self.dataArray[indexPath.row];
        // 列寬
        CGFloat contentWidth = screenWidth-20;
        // 用何種字體進(jìn)行顯示
        UIFont *font = [UIFont systemFontOfSize:13];
        // 計(jì)算size
        CGSize size = [model.comment_content sizeWithFont:font constrainedToSize:CGSizeMake(contentWidth, 1000) lineBreakMode:UILineBreakModeWordWrap];
        
        // 這裏返回需要的高度
        height = size.height+60;
        // 加入數(shù)組
        [self.heightArray addObject:[NSNumber numberWithDouble:height]];
    }
    return height;
}

下拉刷新tableView時(shí)記得清空高度緩存數(shù)組慰毅。
最好的方案:放在model里,拿到數(shù)據(jù)的時(shí)候就提前計(jì)算了



tableView數(shù)據(jù)處理方案

- (void)loadData
{
    self.searchPage = 1;
    [self loadDataGoods:self.searchPage first:YES];
}

- (void)loadDataRefresh
{
    self.searchPage = 1;
    [self loadDataGoods:self.searchPage first:NO];
}

- (void)loadDataMore
{
    self.searchPage++;
    [self loadDataGoods:self.searchPage first:NO];
}

//成功
if (listArray.count < kPageSize) {
    dispatch_async(dispatch_get_main_queue(), ^(){
        [weakSelf.collectionView.mj_footer endRefreshingWithNoMoreData];
    });
}
if (weakSelf.searchPage == 1)
{
    [weakSelf.modeArray removeAllObjects];
    (listArray.count == 0) ? (weakSelf.notDataView.hidden = NO) : (weakSelf.notDataView.hidden = YES);
}
else if (weakSelf.searchPage > 1 && listArray.count == 0)
{
    weakSelf.searchPage--;
}

//失敗
weakSelf.searchPage--;
if (weakSelf.modeArray.count > 0) {
    //處理:吐司
    return;
}
 //處理:第一次加載扎阶,網(wǎng)絡(luò)不給力(重試)事富,加載失敗(重試)乘陪,吐司统台,(mj_footer,mj_header啡邑,hidden = YES)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贱勃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谤逼,更是在濱河造成了極大的恐慌贵扰,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件流部,死亡現(xiàn)場離奇詭異戚绕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)枝冀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門舞丛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來耘子,“玉大人,你說我怎么就攤上這事球切」仁模” “怎么了?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵吨凑,是天一觀的道長捍歪。 經(jīng)常有香客問我,道長鸵钝,這世上最難降的妖魔是什么糙臼? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮恩商,結(jié)果婚禮上弓摘,老公的妹妹穿的比我還像新娘。我一直安慰自己痕届,他們只是感情好韧献,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著研叫,像睡著了一般锤窑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嚷炉,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天渊啰,我揣著相機(jī)與錄音,去河邊找鬼申屹。 笑死绘证,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哗讥。 我是一名探鬼主播嚷那,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼杆煞!你這毒婦竟也來了魏宽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤决乎,失蹤者是張志新(化名)和其女友劉穎队询,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體构诚,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚌斩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了范嘱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片送膳。...
    茶點(diǎn)故事閱讀 40,872評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡员魏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出肠缨,到底是詐尸還是另有隱情逆趋,我是刑警寧澤盏阶,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布晒奕,位于F島的核電站,受9級特大地震影響名斟,放射性物質(zhì)發(fā)生泄漏脑慧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一砰盐、第九天 我趴在偏房一處隱蔽的房頂上張望闷袒。 院中可真熱鬧,春花似錦岩梳、人聲如沸囊骤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽也物。三九已至,卻和暖如春列疗,著一層夾襖步出監(jiān)牢的瞬間滑蚯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工抵栈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留告材,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓古劲,卻偏偏與公主長得像斥赋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子产艾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評論 2 361

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