自動(dòng)計(jì)算cell高度

首先申明一下我的這個(gè)代碼是把第三方的UITableView+FDKeyedHeightCache.m 和 UITableView+FDTemplateLayoutCell抽離出來的,抽離后我個(gè)人認(rèn)為比較簡(jiǎn)單,而且便于理解

1.先上一個(gè)圖片


自定布局.gif

2.基本的代碼是

首先 定義一個(gè)緩存的高度類別 UITableView+LeeKeyedHeightCache
.h 文件

//
//  UITableView+LeeKeyedHeightCache.h
//  動(dòng)態(tài)計(jì)算cell 的高度
//
//  Created by apple on 16/6/13.
//  Copyright ? 2016年 李重陽(yáng). All rights reserved.
//

#import <UIKit/UIKit.h>

/*緩存對(duì)象Cache**/
@interface LeeKeyedHeightCache : NSObject


@end


/*-------------------華麗的分界線-------------------**/
@interface UITableView (LeeKeyedHeightCache)


/*
 * 下面兩個(gè)方法  用戶是可以使用
 * 情況  1.當(dāng)cell 改變的時(shí)候需要?jiǎng)h除緩存高度
        2.當(dāng)cell 刪除咳促、增加 等等,只要index的順序改變了于颖,都要重新改變
 **/
/* 清空某個(gè)Key的緩存的高度 **/
- (void)removeHeightCacheOfCellForKey:(NSString *)key;
/* 清空所有的緩存的高度 **/
- (void)removeAllHeightCacheOfCell;


/*
 * 下面兩個(gè)方法不需要 用戶使用的
 **/
/* 把某個(gè)高度 緩存到 key 中去**/
- (void)cacheCellHeight:(CGFloat)height forKey:(NSString *)key;
/* 從key 中取出某個(gè)高度 **/
- (CGFloat)heightOfCellForKey:(NSString *)key;



@end

.m文件

//
//  UITableView+LeeKeyedHeightCache.m
//  動(dòng)態(tài)計(jì)算cell 的高度
//
//  Created by apple on 16/6/13.
//  Copyright ? 2016年 李重陽(yáng). All rights reserved.
//


#import "UITableView+LeeKeyedHeightCache.h"
#import <objc/runtime.h>

@interface LeeKeyedHeightCache ()

/* 豎著的 高度緩存數(shù)組**/
@property (nonatomic, strong) NSCache *heightValuesForPortrait;
/* 全屏的 高度緩存數(shù)組**/
@property (nonatomic, strong) NSCache *heightValuesForLandscape;


/* 把某個(gè)高度 緩存到 key 中去**/
- (void)cacheHeight:(CGFloat)height forKey:(NSString *)key;
/* 從key 中取出某個(gè)高度 **/
- (CGFloat)heightForKey:(NSString *)key;
/* 清空某個(gè)Key的緩存的高度 **/
- (void)removeHeightForKey:(NSString *)key;
/* 清空所有的緩存的高度 **/
- (void)removeAllHeightCache;


@end

@implementation LeeKeyedHeightCache

#pragma mark - 初始化數(shù)據(jù)
/*初始化數(shù)據(jù)源 **/
- (NSCache *)heightValuesForPortrait {
    
    if (_heightValuesForPortrait == nil) {
        _heightValuesForPortrait = [[NSCache alloc]init];
    }
    return _heightValuesForPortrait;
}

- (NSCache *)heightValuesForLandscape {
    
    if (_heightValuesForLandscape == nil) {
        _heightValuesForLandscape = [[NSCache alloc]init];
    }
    return _heightValuesForLandscape;
}


#pragma mark - 私有方法
/* 判斷出是 豎屏 還是 橫屏中的某個(gè)值 **/
- (NSCache *)heightValuesForCurrentOrientation {
    
    return UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation) ? self.heightValuesForPortrait:self.heightValuesForLandscape;
}

/* 通過number類型轉(zhuǎn)換成CGFloat 類型**/
- (CGFloat)getFloatValueWithNumber:(NSNumber *)number {
    
#if CGFLOAT_IS_DOUBLE
    return [number doubleValue];
#else
    return [number floatValue];
#endif
    
}

#pragma mark - 公共接口

/* 把某個(gè)高度 緩存到 key 中去**/
- (void)cacheHeight:(CGFloat)height forKey:(NSString *)key {
    
    if (height > 0) {
        [self.heightValuesForCurrentOrientation setObject:@(height) forKey:key];
    }
    
}
/* 從key 中取出某個(gè)高度 **/
- (CGFloat)heightForKey:(NSString *)key {
    
    NSNumber * number = [self.heightValuesForCurrentOrientation objectForKey:key];
    return [self getFloatValueWithNumber:number];
}


/* 清空某個(gè)Key的緩存的高度 **/
- (void)removeHeightForKey:(NSString *)key {
    
    [self.heightValuesForPortrait  removeObjectForKey:key];
    [self.heightValuesForLandscape removeObjectForKey:key];
}
/* 清空所有的緩存的高度 **/
- (void)removeAllHeightCache {
    
    [self.heightValuesForPortrait  removeAllObjects];
    [self.heightValuesForLandscape removeAllObjects];
}

@end


/*-------------------華麗的分界線-------------------**/
/* 在類別中加入一個(gè)緩存對(duì)象**/
static const char LeeKeyedHeightCacheKey;


@implementation UITableView (LeeKeyedHeightCache)

- (LeeKeyedHeightCache *)keyedHeighCache {
    
    LeeKeyedHeightCache * cache = objc_getAssociatedObject(self, &LeeKeyedHeightCacheKey);
    if (cache == nil) {
        
        cache = [[LeeKeyedHeightCache alloc]init];
        objc_setAssociatedObject(self, &LeeKeyedHeightCacheKey, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return cache;
}



/* 把某個(gè)高度 緩存到 key 中去**/
- (void)cacheCellHeight:(CGFloat)height forKey:(NSString *)key {
    
    [self.keyedHeighCache cacheHeight:height forKey:key];
}
/* 從key 中取出某個(gè)高度 **/
- (CGFloat)heightOfCellForKey:(NSString *)key {
    
    return [self.keyedHeighCache heightForKey:key];
}

/* 清空某個(gè)Key的緩存的高度 **/
- (void)removeHeightCacheOfCellForKey:(NSString *)key {
    
    [self.keyedHeighCache removeHeightForKey:key];
}
/* 清空所有的緩存的高度 **/
- (void)removeAllHeightCacheOfCell {
    
    [self.keyedHeighCache removeAllHeightCache];
}




@end

接下來定義一個(gè)計(jì)算高度的類別UITableView+LeeAutoLayoutCell
.h文件

//
//  UITableView+LeeAutoLayoutCell.h
//  動(dòng)態(tài)計(jì)算cell 的高度
//
//  Created by apple on 16/6/13.
//  Copyright ? 2016年 李重陽(yáng). All rights reserved.
//

#import <UIKit/UIKit.h>
#import "UITableView+LeeKeyedHeightCache.h"

@interface UITableView (LeeAutoLayoutCell)

/* 返回自動(dòng)布局cell的高度**/
- (CGFloat)heightForAutoLayoutCellWithIdentifier:(NSString *)identifier
                                     cacheForKey:(NSString *)key
                                   configuration:(void (^)(id cell))configuration;


@end

.m 文件


//
//  UITableView+LeeAutoLayoutCell.m
//  動(dòng)態(tài)計(jì)算cell 的高度
//
//  Created by apple on 16/6/13.
//  Copyright ? 2016年 李重陽(yáng). All rights reserved.
//

#import "UITableView+LeeAutoLayoutCell.h"
#import <objc/runtime.h>

static const char cellCacheKey;
@implementation UITableView (LeeAutoLayoutCell)

#pragma mark - 私有方法
/* 通過自動(dòng)布局 來計(jì)算cell的高度 **/
- (CGFloat)heightForCellWithIdentifier:(NSString *)identifier configuration:(void (^)(id cell))configuration {
    
    UITableViewCell *cell = [self cellForReuseIdentifier:identifier];
    /*手動(dòng)調(diào)用確保cell 在顯示屏幕中 **/
    [cell prepareForReuse];
    /*需要把這個(gè)cell 傳遞出去 **/
    if (configuration) {
        configuration(cell);
    }
    /* 獲得cell 的寬度 **/
    CGFloat contentViewWidth = CGRectGetWidth(self.frame);
    
    
    /* 修復(fù)cell 的寬度 **/
    if (cell.accessoryView) {
        contentViewWidth -= 16 + CGRectGetWidth(cell.accessoryView.frame);
    } else {
        static const CGFloat systemAccessoryWidths[] = {
            [UITableViewCellAccessoryNone] = 0,
            [UITableViewCellAccessoryDisclosureIndicator] = 34,
            [UITableViewCellAccessoryDetailDisclosureButton] = 68,
            [UITableViewCellAccessoryCheckmark] = 40,
            [UITableViewCellAccessoryDetailButton] = 48
        };
        contentViewWidth -= systemAccessoryWidths[cell.accessoryType];
    }
    
    if (contentViewWidth <= 0) {
        return 0;
    }
    
    CGSize fittingSize = CGSizeZero;
    
    /* 因?yàn)閘abel 換行的時(shí)候 需要知道contentView 的最大的寬度 
     * 這個(gè)方法很good
     **/
    NSLayoutConstraint *tempWidthConstraint = [NSLayoutConstraint constraintWithItem:cell.contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:contentViewWidth];
    [cell.contentView addConstraint:tempWidthConstraint];
    // 自動(dòng)布局的系統(tǒng)方法 計(jì)算高度
    fittingSize = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    /* 計(jì)算完后 再刪除 **/
    [cell.contentView removeConstraint:tempWidthConstraint];
    /* 修復(fù) 線 的1個(gè)像素 **/
    if (self.separatorStyle != UITableViewCellSeparatorStyleNone) {
        fittingSize.height += 1.0 / [UIScreen mainScreen].scale;
    }
    return fittingSize.height;
    
}

/* 獲取 cell **/
- (UITableViewCell *)cellForReuseIdentifier:(NSString *)identifier {
    
    NSCache * cellCache = objc_getAssociatedObject(self, &cellCacheKey);
    if (cellCache == nil) {
        cellCache = [[NSCache alloc]init];
        objc_setAssociatedObject(self, &cellCacheKey, cellCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    UITableViewCell *cell = [cellCache objectForKey:identifier];
    if (cell == nil) {
        cell = [self dequeueReusableCellWithIdentifier:identifier];
        /* cell 如果是nil 就報(bào)一個(gè)錯(cuò)誤:提示用戶應(yīng)該要在tableView 注冊(cè)cell**/
        NSAssert(cell != nil, @"Cell must be registered to table view for identifier - %@", identifier);
        cell.contentView.translatesAutoresizingMaskIntoConstraints = NO;
        [cellCache setObject:cell forKey:identifier];
    }
    return cell;
    
}

#pragma mark - 公共方法
/* 返回自動(dòng)布局cell的高度**/
- (CGFloat)heightForAutoLayoutCellWithIdentifier:(NSString *)identifier
                                     cacheForKey:(NSString *)key
                                   configuration:(void (^)(id cell))configuration {
    
    if (identifier.length == 0 || key.length == 0) {
        return 0;
    }
    /*先從緩存中取 **/
    CGFloat cachedHeight = [self heightOfCellForKey:key];
    if (cachedHeight >0) {
        return cachedHeight;
    }else {
        //計(jì)算cell 的高度并且緩存進(jìn)去
        CGFloat height = [self heightForCellWithIdentifier:identifier configuration:configuration];
        /* 緩存cell的高度**/
        [self cacheCellHeight:height forKey:key];
        return height;
    }
    
}

@end


3.計(jì)算高度和邏輯交互

計(jì)算高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    
    return [self.tableView heightForAutoLayoutCellWithIdentifier:@"MasCell" cacheForKey:[NSString stringWithFormat:@"MasCell%ld_%ld",indexPath.section,indexPath.row] configuration:^(MasCell *cell) {
        /*cell  需要重新布局 **/
        cell.model = self.dataArr[indexPath.row];
    }];
    
    
}

點(diǎn)擊事件的處理

 /* 刪除所有的 cell 的高度緩存**/
    [self.tableView removeAllHeightCacheOfCell];
    [self.tableView reloadData];

github 中的包內(nèi)容

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末邻遏,一起剝皮案震驚了整個(gè)濱河市滴须,隨后出現(xiàn)的幾起案子台猴,更是在濱河造成了極大的恐慌朽合,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卿吐,死亡現(xiàn)場(chǎng)離奇詭異旁舰,居然都是意外死亡锋华,警方通過查閱死者的電腦和手機(jī)嗡官,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來毯焕,“玉大人衍腥,你說我怎么就攤上這事∧擅ǎ” “怎么了婆咸?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)芜辕。 經(jīng)常有香客問我尚骄,道長(zhǎng),這世上最難降的妖魔是什么侵续? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任倔丈,我火速辦了婚禮,結(jié)果婚禮上状蜗,老公的妹妹穿的比我還像新娘需五。我一直安慰自己,他們只是感情好轧坎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布宏邮。 她就那樣靜靜地躺著,像睡著了一般缸血。 火紅的嫁衣襯著肌膚如雪蜜氨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天捎泻,我揣著相機(jī)與錄音记劝,去河邊找鬼。 笑死族扰,一個(gè)胖子當(dāng)著我的面吹牛厌丑,可吹牛的內(nèi)容都是我干的定欧。 我是一名探鬼主播,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼怒竿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼砍鸠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耕驰,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤爷辱,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后朦肘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饭弓,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年媒抠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弟断。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡趴生,死狀恐怖阀趴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苍匆,我是刑警寧澤刘急,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站浸踩,受9級(jí)特大地震影響叔汁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜检碗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一据块、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧后裸,春花似錦瑰钮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至因苹,卻和暖如春苟耻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扶檐。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工凶杖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人款筑。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓智蝠,卻偏偏與公主長(zhǎng)得像腾么,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杈湾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

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