簡潔高效的一套iOS列表框架GYTableViewController

来源:https://www.cnblogs.com/gaoyangclub/archive/2018/03/30/8616497.html
-Advertisement-
Play Games

自定義封裝UITableView,更加簡潔高效,無需為了實現delegate增加膠水代碼,自帶下拉刷新上拉載入控制項 "項目倉庫地址" 歡迎互相交流學習,問題交流群群號:296406818 如何開始 "項目技術特點" "安裝方法" "框架用法" 代碼結構 "GYTableBaseView.h" "GY ...


自定義封裝UITableView,更加簡潔高效,無需為了實現delegate增加膠水代碼,自帶下拉刷新上拉載入控制項

項目倉庫地址

歡迎互相交流學習,問題交流群群號:296406818

技術特點

  • Section和Cell層次更加清晰,根據傳入的Section數據結構內部已經全部實現Section和Cell相關delegate方法
  • Cell實例可獲得外部動態數據,索引位置,上下關係,選中狀態等,隨時更換樣式
  • Controller自帶MJRefresh框架,提供下拉刷新和上拉載入功能,外部暴露介面調用
  • 提供Cell,Section間距設置,提供選中行高亮、選中行自動居中,提供設置Cell動態高度設置等API
  • 框架中的元素全部繼承於原生的tableView相關元素,除部分代理方法外,其他原生方法扔然可以使用

安裝方法

  • pod安裝: pod 'GYTableViewController'
  • 手動安裝:手動安裝需要添加兩個庫,將GYTableViewController項目文件中Framework文件下的文件導入自身項目,同時此框架基於MJRefresh,所以也需要導入MJRefresh框架文件,手動或者pod都可以,MJRefresh安裝方法

框架用法

請使用該框架中的元素來代替原生列表控制項,對應關係如下:

GYTableBaseView -> UITableView
GYTableViewController -> UITableViewController
GYTableViewCell -> UITableViewCell
GYTableViewSection 原生使用UIView展示section內容,這裡使用GYTableViewSection
SectionVo 用來設置Section樣式與GYTableViewSection實例綁定
CellVo 用來設置Cell樣式與GYTableViewCell實例綁定

使用時有列表控制項的界面直接繼承GYTableViewController,.h示例如下

#import "GYTableViewController.h"
@interface NormalTableViewController : GYTableViewController

.m文件中重寫headerRefresh添加元素,當自帶的下拉刷新控制項下拉時調用;從而開始列表內容層次搭建,以及各種類型的Cell位置如何擺放等

-(void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler{
    //下拉刷新後開始請求後臺提供數據,請求到數據後根據解析的內容展開cell實例和位置等操作,代碼結構如下(偽代碼)
    request{
        tableView{
            sectionVo{
                cellVo,
                cellVo,
                ...
            }
            sectionVo{
                cellVo,
                ...
            }
            ...
        }
        endRefreshHandler();//界面搭建完畢後停止刷新
    }
}

Cell控制項直接繼承GYTableViewCell,.h示例如下

#import "GYTableViewCell.h"
@interface NormalViewCell : GYTableViewCell

.m文件中重寫showSubviews方法進行佈局,利用GET_CELL_DATA或GET_CELL_ARRAY_DATA巨集來獲取列表控制項中傳入的數據,如傳入非數組型的數據使用GET_CELL_DATA,反之使用GET_CELL_ARRAY_DATA

-(void)showSubviews{
    GET_CELL_DATA([xxx class]);//先獲取外部傳入的數據
    GET_CELL_ARRAY_DATA([xxx class]);//或者獲取數組類型的數據

    //開始界面佈局...
}

GYTableBaseView.h

@interface GYTableBaseView : UITableView

/** 設置選中位置 **/
@property(nonatomic,retain) NSIndexPath* selectedIndexPath;
/** 點中cell高亮 **/
@property (nonatomic,assign) BOOL clickCellHighlight;
/** 點中cell自動居中 **/
@property (nonatomic,assign) BOOL clickCellMoveToCenter;
/** 每一節間距 **/
@property (nonatomic,assign) CGFloat sectionGap;
/** 每個cell間距 **/
@property (nonatomic,assign) CGFloat cellGap;
/** 首次下拉 **/
@property (nonatomic,assign,readonly) BOOL hasFirstRefreshed;

/** 下拉刷新 **/
-(void)headerBeginRefresh;
/** 檢查數據間距 **/
-(void)checkGaps;
/** 清除所有數據 **/
-(void)clearAllSectionVo;
/** 添加一節內容 **/
-(void)addSectionVo:(SectionVo*)sectionVo;
/** 在某個索引插入一節內容 **/
-(void)insertSectionVo:(SectionVo*)sectionVo atIndex:(NSInteger)index;
/** 刪除一節內容 **/
-(void)removeSectionVoAt:(NSInteger)index;
/** 重新刷新全部界面 類似源生的reloadData **/
-(void)reloadGYData;
/** 將選中的數據項平滑居中移動 **/
-(void)moveSelectedIndexPathToCenter;

/** 獲取最後一個SectionVo **/
-(SectionVo*)getLastSectionVo;
/** 獲取第一個SectionVo **/
-(SectionVo*)getFirstSectionVo;
/** 獲取目標索引位置SectionVo **/
-(SectionVo*)getSectionVoByIndex:(NSInteger)index;
/** 獲取目標indexPath位置CellVo **/
-(CellVo*)getCellVoByIndexPath:(NSIndexPath*)indexPath;
/** 獲取SectionVo總數 **/
-(NSUInteger)getSectionVoCount;
/** 獲取CellVo總數 所有SectionVo包含的CellVo總和 **/
-(NSUInteger)getTotalCellVoCount;

@end

SectionVo

@interface SectionVo : NSObject

/** 創建SectionVo實例並初始化設置下一步回調 **/
+ (instancetype)initWithParams:(void(^)(SectionVo* svo))nextBlock;
/** 創建SectionVo實例並初始化設置section頁眉高度、section頁眉類型、section頁眉數據、下一步回調 **/
+ (instancetype)initWithParams:(CGFloat)sectionHeaderHeight sectionHeaderClass:(Class)sectionHeaderClass sectionHeaderData:(id)sectionHeaderData nextBlock:(void(^)(SectionVo* svo))nextBlock;
/** 創建SectionVo實例並初始化設置section頁眉高度、section頁眉類型、section頁眉數據、section頁腳高度、section頁腳類型、section頁腳數據、下一步回調 **/
+ (instancetype)initWithParams:(CGFloat)sectionHeaderHeight sectionHeaderClass:(Class)sectionHeaderClass sectionHeaderData:(id)sectionHeaderData sectionFooterHeight:(CGFloat)sectionFooterHeight sectionFooterClass:(Class)sectionFooterClass sectionFooterData:(id)sectionFooterData nextBlock:(void(^)(SectionVo* svo))nextBlock;

/** GYTableViewSection頁眉實例高度 **/
@property (nonatomic,assign)CGFloat sectionHeaderHeight;
/** 用來實例化GYTableViewSection頁眉的自定義類型 **/
@property (nonatomic,retain)Class sectionHeaderClass;
/** 傳遞給GYTableViewSection頁眉實例的數據,用來展示界面判斷邏輯等,實例內部通過self.data屬性獲得 **/
@property (nonatomic,retain)id sectionHeaderData;

/** GYTableViewSection頁腳實例高度 **/
@property (nonatomic,assign)CGFloat sectionFooterHeight;
/** 用來實例化GYTableViewSection頁腳的自定義類型 **/
@property (nonatomic,retain)Class sectionFooterClass;
/** 傳遞給GYTableViewSection頁腳實例的數據,用來展示界面判斷邏輯等,實例內部通過self.data屬性獲得 **/
@property (nonatomic,retain)id sectionFooterData;

/** 該節包含的CellVo個數 **/
-(NSInteger)getCellVoCount;
/**  添加單個CellVo **/
-(void)addCellVo:(CellVo*)cellVo;
/**  批量添加CellVo **/
-(void)addCellVoByList:(NSArray<CellVo*>*)otherVoList;

@end

CellVo

@interface CellVo : NSObject

/** 創建CellVo實例並初始化設置cell高度、cell類型、cell數據 **/
+ (instancetype)initWithParams:(CGFloat)cellHeight cellClass:(Class)cellClass cellData:(id)cellData;
/** 創建CellVo實例並初始化設置cell高度、cell類型、cell數據、cell是否唯一 **/
+ (instancetype)initWithParams:(CGFloat)cellHeight cellClass:(Class)cellClass cellData:(id)cellData isUnique:(BOOL)isUnique;
/** 創建CellVo實例並初始化設置cell高度、cell類型、cell數據、cell是否唯一、是否強制刷新 **/
+ (instancetype)initWithParams:(CGFloat)cellHeight cellClass:(Class)cellClass cellData:(id)cellData isUnique:(BOOL)isUnique forceUpdate:(BOOL)forceUpdate;
/** 通過原始數據數組批量創建CellVo並將數據分別對應存入 **/
+(NSArray<CellVo*>*)dividingCellVoBySourceArray:(CGFloat)cellHeight cellClass:(Class)cellClass sourceArray:(NSArray*)sourceArray;

/** GYTableViewCell實例高度 **/
@property (nonatomic,assign)CGFloat cellHeight;
/** 用來實例化GYTableViewCell的自定義類型 **/
@property (nonatomic,retain)Class cellClass;
/** 傳遞給GYTableViewCell實例的數據,用來展示界面判斷邏輯等,實例內部通過self.data屬性獲得 **/
@property (nonatomic,retain)id cellData;
/** 創建GYTableViewCell實例唯一,相當於單例,就算是相同類型的GYTableViewCell也是各自成為單例,且內容不會刷新(適合內容只初始化一次的界面) **/
@property (nonatomic,assign)BOOL isUnique;
/** isUnique設置為true的情況下 forceUpdate可以繼續讓單例GYTableViewCell中的內容強制刷新 **/
@property (nonatomic,assign)BOOL forceUpdate;
/** 自定義保留欄位 **/
@property (nonatomic,copy)NSString* cellName;

@end

GYTableViewController.h

@interface GYTableViewController : UIViewController<GYTableBaseViewDelegate>

/** controller包含的tableView實例 **/
@property(nonatomic,retain)GYTableBaseView* tableView;
/** 設置進入該頁面是否自動下拉刷新 預設true **/
@property(nonatomic,assign)BOOL autoRefreshHeader;
/** 設置選中某個indexPath位置 **/
@property(nonatomic,retain)NSIndexPath* selectedIndexPath;
/** 設置是否標記重用cell實例 預設true **/
@property(nonatomic,assign)BOOL useCellIdentifer;
/** 設置每次進入該頁面自動滾動到列表頂部 預設false **/
@property(nonatomic,assign)BOOL autoRestOffset;
/** 設置是否顯示下拉刷新控制項 預設true **/
@property(nonatomic,assign)BOOL isShowHeader;
/** 設置是否顯示上拉載入控制項 預設false **/
@property(nonatomic,assign)BOOL isShowFooter;

/** 設置TableView的佈局位置,預設鋪滿Controller **/
-(CGRect)getTableViewFrame;
/** 設置自定義下拉刷新控制項實例 **/
-(MJRefreshHeader*)getRefreshHeader;
/** 設置自定義上拉載入控制項實例 **/
-(MJRefreshFooter*)getRefreshFooter;

@end

GYTableBaseViewDelegate

/** 下拉刷新或上拉載入調用結束Block hasData標註界面是否刷新出了新的數據  **/
typedef void(^HeaderRefreshHandler)(BOOL hasData);
typedef void(^FooterLoadMoreHandler)(BOOL hasData);

@protocol GYTableBaseViewDelegate<UITableViewDelegate,UITableViewDataSource>

@optional
/** 當GYTableBaseView下拉刷新時代理調用 **/
-(void)headerRefresh:(GYTableBaseView*)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler;
@optional
/** 當GYTableBaseView上拉載入時代理調用 **/
-(void)footerLoadMore:(GYTableBaseView*)tableView endLoadMoreHandler:(FooterLoadMoreHandler)endLoadMoreHandler lastSectionVo:(SectionVo*)lastSectionVo;
@optional
/** 當GYTableBaseView下拉刷新完畢後代理調用 **/
-(void)didRefreshComplete:(GYTableBaseView*)tableView;
@optional
/** 當GYTableBaseView上拉載入完畢後代理調用 **/
-(void)didLoadMoreComplete:(GYTableBaseView*)tableView;
@optional
/** 當GYTableBaseView某一條GYTableViewCell實例被點擊時代理調用 **/
-(void)tableView:(GYTableBaseView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
@optional
/** 當GYTableBaseView滾動到某個位置時代理調用 **/
-(void)didScrollToRow:(GYTableBaseView*)tableView indexPath:(NSIndexPath *)indexPath;
@optional
/** 當GYTableBaseView從滾動狀態靜止時代理調用 **/
-(void)didEndScrollingAnimation:(GYTableBaseView*)tableView;

@end

GYTableViewCell.h

@interface GYTableViewCell : UITableViewCell

/** 是否在該節中的首位 **/
@property(nonatomic,assign) BOOL isFirst;
/** 是否在該節中的末位 **/
@property(nonatomic,assign) BOOL isLast;
/** 是否在該節只有此一個GYTableViewCell實例 **/
@property(nonatomic,assign) BOOL isSingle;
/** 是否需要刷新界面 **/
@property(nonatomic,assign) BOOL needRefresh;
/** 是否初次界面載入完畢 **/
@property(nonatomic,assign) BOOL isSubviewShow;
/** 對應的GYTableBaseView實例 **/
@property(nonatomic,weak) GYTableBaseView* tableView;
/** 當前所處位置 **/
@property(nonatomic,retain) NSIndexPath* indexPath;
/** 對應的CellVo實例 **/
@property(nonatomic,retain) CellVo *cellVo;

/** 頁面元素創建並佈局 請勿使用layoutSubviews來佈局 **/
-(void)showSubviews;
/** 是否顯示選中的效果樣式 預設false **/
-(BOOL)showSelectionStyle;
/** 根據內容動態計算高度(適合內容多少高度不定的樣式或文案展示) **/
-(CGFloat)getCellHeight:(CGFloat)cellWidth;
/** 檢查cellData的類型是否是目標類型 並返回cellData **/
-(id)checkCellDataClass:(Class)targetClass;
/** 檢查cellData類型為NSArray中的子元素類型是否是目標類型 並返回cellData **/
-(NSArray*)checkCellArrayDataClass:(Class)arrayMemberClass;

@end

GYTableViewSection.h

@interface GYTableViewSection : UIControl

/** tableView所有section總數  **/
@property(nonatomic,assign)NSInteger sectionCount;
/** 當前section索引位置  **/
@property(nonatomic,assign)NSInteger sectionIndex;
/** 外部傳入的數據 用來佈局或交互等(sectionVo.sectionData) **/
@property(nonatomic,retain)id data;
/** 是否在整個tableView的首位 **/
@property(nonatomic,assign)BOOL isFirst;
/** 是否在整個tableView的末位 **/
@property(nonatomic,assign)BOOL isLast;

@end

添加Cell

列表控制器內部實現

-(void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler{
    [tableView addSectionVo:[SectionVo initWithParams:^(SectionVo *svo) {
        //添加一個高度為230,類型為BannerViewCell,展示banner圖片列表的Cell
        [svo addCellVo:[CellVo initWithParams:230 cellClass:RefreshBannerViewCell.class cellData:self.bannerUrlGroup]];
    }]];
    endRefreshHandler(YES);//不要忘了結束刷新,否則刷新動畫會停留原地
}

案例1-1

批量添加Cell

列表控制器內部實現

-(void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler{
    [tableView addSectionVo:[SectionVo initWithParams:^(SectionVo *svo) {
        //添加一個高度為230,類型為BannerViewCell,展示banner圖片列表的Cell
        [svo addCellVo:[CellVo initWithParams:230 cellClass:RefreshBannerViewCell.class cellData:self.bannerUrlGroup]];
    }]];
    //註意banner和基金產品列表屬於不同區域,應存放到各自section中添加,管理section視圖會比較方便
    [tableView addSectionVo:[SectionVo initWithParams:^(SectionVo *svo) {
        //添加多個高度為80,類型為RefreshFundViewCell,展示基金信息的Cell
        [svo addCellVo:[CellVo initWithParams:80 cellClass:RefreshFundViewCell.class cellData:self.fundModels[0]]];
        [svo addCellVo:[CellVo initWithParams:80 cellClass:RefreshFundViewCell.class cellData:self.fundModels[1]]];
        [svo addCellVo:[CellVo initWithParams:80 cellClass:RefreshFundViewCell.class cellData:self.fundModels[2]]];
        //...
    }]];
    endRefreshHandler(YES);//不要忘了結束刷新,否則刷新動畫會停留原地
}

相同類型的Cell添加可以修改成通過原數組批量添加

[tableView addSectionVo:[SectionVo initWithParams:^(SectionVo *svo) {
    //添加多個高度為80,類型為RefreshFundViewCell,展示基金信息的Cell
    [svo addCellVoByList:[CellVo dividingCellVoBySourceArray:80 cellClass:RefreshFundViewCell.class sourceArray:self.fundModels]];
}]];

案例1-2

添加Section

如果一節內容需要添加section頁眉視圖,只要在sectionVo實例設置sectionHeaderClass即可,同理section頁腳設置sectionFooterClass

-(void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler{
    [tableView addSectionVo:[SectionVo initWithParams:36 sectionHeaderClass:RefreshFundViewSection.class sectionHeaderData:@"精品專區" nextBlock:^(SectionVo *svo) {
        //添加section內的cell...
    }]];
    endRefreshHandler(YES);
}

分類結構如下

靜態圖

案例1-3

isUnique唯一性

預設所有相同Class的Cell實例都是相互復用,每次下拉刷新或者table設置reloadData,被覆用的Cell實例都會重新觸發刷新調用showSubviews,從而根據傳遞的data展開;然而,一些特殊的Cell不需要復用或只實例化一次,比如標簽按鈕區域的Cell或者banner區域的Cell,每次下拉都是只用這個實例,可以設置為isUnique作為唯一Cell實例優化提高性能

-(void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler{
    [tableView addSectionVo:[SectionVo initWithParams:^(SectionVo *svo) {
       //添加一個高度為230,類型為BannerViewCell,展示banner圖片列表的Cell
        [svo addCellVo:[CellVo initWithParams:230 cellClass:RefreshBannerViewCell.class cellData:self.bannerUrlGroup isUnique:YES]];
        //添加一個高度為90,類型為RefreshHotViewCell,展示banner圖片列表的Cell
        [svo addCellVo:[CellVo initWithParams:90 cellClass:RefreshHotViewCell.class cellData:self.hotModels isUnique:YES]];
    }]];
    endRefreshHandler(YES);
}

調用上拉載入

列表控制器內部設置顯示上拉載入控制器

-(BOOL)isShowFooter{
    return YES;
}

列表控制器內部重寫footerLoadMore

//endLoadMoreHandler:結束刷新回調block,lastSectionVo:上一節sectionVo數據,即當前列表頁最後一節
-(void)footerLoadMore:(GYTableBaseView *)tableView endLoadMoreHandler:(FooterLoadMoreHandler)endLoadMoreHandler lastSectionVo:(SectionVo *)lastSectionVo{
    [lastSectionVo addCellVoByList:[CellVo dividingCellVoBySourceArray:80 cellClass:RefreshFundViewCell.class sourceArray:self.fundNewModels]];//將新增的CellVo實例繼續添加到上一節SectionVo實例中
    endLoadMoreHandler(YES);
}

根據需求添加到列表頁最後一節,或者添加到新的一節數據中,並設置添加上限

if([tableView getTotalCellVoCount] > 30){//總共超出30條數據不添加數據
    endLoadMoreHandler(NO);//直接結束上拉載入刷新,並顯示"已經全部載入完畢"
    return;
}
//根據業務需求的不同,可以繼續添加到上一節sectionVo,也可以添加到新的一節sectionVo中
if([lastSectionVo getCellVoCount] < 15){//上一節少於15條繼續添加到上一節sectionVo
    [lastSectionVo addCellVoByList:[CellVo dividingCellVoBySourceArray:80 cellClass:RefreshFundViewCell.class sourceArray:self.fundNewModels]];
}else{//上一節超了 添加到新的一節sectionVo
    [tableView addSectionVo:[SectionVo initWithParams:36 sectionHeaderClass:RefreshFundViewSection.class sectionHeaderData:@"推薦專區" nextBlock:^(SectionVo *svo) {
        [svo addCellVoByList:[CellVo dividingCellVoBySourceArray:80 cellClass:RefreshFundViewCell.class sourceArray:self.fundNewModels]];
    }]];
}
endLoadMoreHandler(YES);//不要忘了結束上拉載入刷新

案例1-4

更改UITableView的frame

列表控制器內部重寫getTableViewFrame

如存在和容器底部對齊的元素,請在此方法對齊底部位置(預設占滿controller邊界);autoLayerout無需重寫此方法,自行設置tableView和其他元素佈局關係

-(CGRect)getTableViewFrame{
    self.noticeBack.frame = CGRectMake(0, 0, self.view.width, 30);
    self.submitButton.maxY = self.view.height;//底部按鈕對齊容器底部
    //返回設置好的tableView位置frame 高度=總高度-公告區高-底部按鈕高
    return CGRectMake(0, self.noticeBack.height, self.view.width, self.view.height - self.noticeBack.height - self.submitButton.height);
}

案例2-1

自定義下拉刷新控制項

列表控制器內部重寫getRefreshHeader

-(MJRefreshHeader *)getRefreshHeader{
    return [[DiyRotateRefreshHeader alloc]init];
}

案例2-2

偵聽選中的Cell

列表控制器內部實現代理,原生的方法一致

-(void)tableView:(GYTableBaseView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    CellVo* cvo = [tableView getCellVoByIndexPath:indexPath];//獲取到綁定的CellVo
    XXClass* cellData = cvo.cellData;//獲得cell的原始數據
    //根據數據添加業務邏輯...
}

設置cell點擊效果,cell實例內部重寫showSelectionStyle

-(BOOL)showSelectionStyle{
    return YES;
}

案例2-3

設置Cell或Section元素間距

列表控制器內部設置tableView屬性cellGap或sectionGap

- (void)viewDidLoad {
    self.tableView.sectionGap = 6;//設置每一節區域之間間距
    self.tableView.cellGap = 3;//設置每個Cell之間間距(包含每一節區域)
}

案例3-1

設置選中某個位置的Cell

當刷新完成後設置,列表控制器內部設置tableView屬性selectedIndexPath

-(void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler{
     [tableView addSectionVo:[SectionVo initWithParams:^(SectionVo *svo) {
        //..添加cell數據
     }]];
     tableView.selectedIndexPath = [NSIndexPath indexPathForRow:0 inSection:0];//設置選中某個indexPath
     endRefreshHandler(YES);    
}

Cell實例設置選中效果,重寫setSelected方法,選中樣式請根據需求自行添加

-(void)setSelected:(BOOL)selected{
    [super setSelected:selected];
    [self checkCellRelate];//自定義選中樣式方法,非框架內部方法,實現如下
}

Cell實例位置關係isFirst,isLast,位於第一個或最後一個和中間段的Cell樣式不同

-(void)checkCellRelate{
    if (self.isFirst) {
        [self drawFirstStyle:nodeColor];
    }else if(self.isLast){
        [self drawLastStyle:nodeColor];
    }else{
        [self drawNormalStyle:nodeColor];
    }
}

案例4-1

設置交互點擊某個位置Cell並高亮

- (void)viewDidLoad {
    self.tableView.clickCellHighlight = YES;
}

案例4-2

設置點擊Cell自動居中

- (void)viewDidLoad {
    self.tableView.clickCellMoveToCenter = YES;
}

案例4-3

Cell自動調整高度

列表控制器內部設置CellVo傳入高度CELL_AUTO_HEIGHT

-(void)headerRefresh:(GYTableBaseView *)tableView endRefreshHandler:(HeaderRefreshHandler)endRefreshHandler{
     [tableView addSectionVo:[SectionVo initWithParams:^(SectionVo *svo) {
         [svo addCellVoByList:[CellVo dividingCellVoBySourceArray:CELL_AUTO_HEIGHT cellClass:AutoHeightWeiboCell.class sourceArray:self.weiboModels]];
     }]];
     endRefreshHandler(YES);  
}

Cell實例重寫getCellHeight方法獲取動態高度,獲取高度內容會被緩存不會二次計算

-(CGFloat)getCellHeight:(CGFloat)cellWidth{
    WeiboModel* weiboModel = GET_CELL_DATA(WeiboModel.class);//獲取Model
    NSString* content = weiboModel.content;//獲取動態內容字元串
    CGRect contentSize = [content boundingRectWithSize:CGSizeMake(cellWidth - LEFT_PADDING - RIGHT_PADDING, FLT_MAX)
                             options:NSStringDrawingUsesLineFragmentOrigin
                          attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:SIZE_TEXT_SECONDARY]}
                             context:nil];//計算給定範圍內最佳尺寸
    return TOPIC_AREA_HEIGHT + contentSize.size.height + IMAGE_AREA_HEIGHT + BOTTOM_PADDING * 2;//返回計算後的最終高度
}

案例5-1

歡迎互相交流學習,問題交流群群號:296406818


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天遇到一個關於MySQL求助的問題,修改表結構時遇到“ERROR 1050 (42S01): table xxx already exits" mysql> ALTER TABLE DAY_BOOK_REPORT ADD UNIT_PRICE_PCS DOUBLE(12,2) DEFAULT NU... ...
  • 1、去官網下載MySQL,https://dev.mysql.com/downloads/mysql/5.6.html#downloads 選擇redhat6 64bit 下載rpm bundle 2、將文件拷貝到centos,解壓 tar -xvf MySQL-5.6.39-1.el6.x86_6 ...
  • 從Google首席執行官埃里克·施密特(Eric Schmidt)首次提出“ 雲計算 ”(cloud computing)的概念到現在,雲計算已經走過了炒作期和實踐期,已經處於成熟期。同時,行業集中度也越來越高並呈逐漸加強的趨勢,目前業內大公司已經占據了整個市場的半壁江山。 Synergy Rese ...
  • 蘋果在關於後臺模式的文檔中稱:“這個配置項應該儘可能少的使用,而且最好只給那些提供通知服務的應用使用。如果有在後臺運行的替代方法,就應該使用替代方法。比如,如果應用能使用顯著位置變化介面來接受位置變動事件的話,就不要將應用註冊為需要在後臺監控位置變化的應用。 這個配置項可選的值有:audio,loc ...
  • 經過進兩周的持續發酵,Facebook5000萬用戶數據泄露事件,已讓其處在輿論的風尖浪口。對於手機APP泄漏用戶個人隱私問題,再次受到人們的關註。對於這個問題,你會怎麼看? 隱私,即不願公開的個人信息,前幾日,百度CEO李彥巨集在某論壇上說了一段引發爭議的話:“假如他們願意用隱私交換便捷性或者效率的 ...
  • 要瞭解TextView對文本的繪製,那麼就需要瞭解Paint.FontMetircs。 官方對該類的解釋是:Class that describes the various metrics for a font at a given text size., 意思是說,這玩意兒是繪製文本內容時存儲該文 ...
  • RxJava2已經推出有一年半的時間,由於之前RxJava已經在現有項目中廣泛使用,而RxJava2在除了很多命名外並沒有太多革新,所以相信有很多人跟我一樣都還沒有升級. 隨著老版本漸漸的失去維護,更重要的是有一定時間允許我來做這個遷移,其實棄老從新一直都是程式員的喜好. ...
  • 其中有一個不太規則的label: image.png image.png 這個label頂部的兩個角是圓角,底部的兩個角是直角,底部還有一個小三角。 思路 CAShapeLayer聯合UIBezierPath畫一個不規則的layer作為label.layer的mask。 具體實現 1.自定義一個繼承 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...