GYTableViewController

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

自定義封裝UITableView,更加簡潔高效,無需為了實現delegate增加膠水代碼,自帶下拉刷新上拉載入控制項 "項目倉庫地址" 如何開始 "項目技術特點" "安裝方法" "框架用法" 代碼結構 "GYTableBaseView.h" "GYTableViewController.h" "GYT ...


自定義封裝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
更多相關文章
  • 的 說明DBA負責的安全和審計工作 啟用標準資料庫審計 指定審計選項 複查審計信息 維護審計線索 《Oracle Database Concepts》《Oracle資料庫管理員指南》《Oracle 資料庫安全性指南》 責任分離 責任分離的主要要求 DBA必須是可信任的,同時也必須承擔責任(考慮因素) ...
  • 怎麼玩:1.配從庫不賠主庫2.從庫配置:slaceof 主庫IP主庫埠在沒有SLAVEOF之前,三個機器處於都是master的角色,但是當執行SLAVEOF之後,主機的角色就是role,從機的角色就是slave,執行SLAVEOF之後,會把主機上的所有數據按照主從複製的原則複製一份,並且從機上不能 ...
  • 一.About Mysql 1.Mysql 優點 體積小、速度快、開放源碼、免費 一般中小型網站的開發都選擇 MySQL ,最流行的關係型資料庫 LAMP / LNMP 體積小、速度快、開放源碼、免費 一般中小型網站的開發都選擇 MySQL ,最流行的關係型資料庫 LAMP / LNMP Linux ...
  • 一、RDD概念與特性 1. RDD的概念 RDD(Resilient Distributed Dataset),是指彈性分散式數據集。數據集:Spark中的編程是基於RDD的,將原始數據載入到記憶體變成RDD,RDD再經過若幹次轉化,仍為RDD。分散式:讀數據一般都是從分散式系統中去讀,如hdfs、k ...
  • 實驗環境:CentOS 7.4 mysql軟體: mysql-boost-5.7.20.tar.gz 1.安裝編譯工具 yum -y install \ncurses \ncurses-devel \bison \cmake\gcc \gcc-c++ \make 2.解壓包 tar xf mysql ...
  • 一.delete誤刪 方法1:如果表結構沒有改變,直接閃回整個表,具體步驟: --首先需要表閃回許可權,開啟行移動功能 alter table 表名 enable row movement; --執行閃回恢復表數據到某個時間點 flashback table 表名 to timestamp to_ti ...
  • 創建觸發器 是特殊的存儲過程,自動執行,一般不要有返回值 類型: 1.後觸發器 (AFTER,FOR)先執行對應語句,後執行觸發器中的語句 2.前觸發器 並沒有真正的執行觸發語句(insert,update,delete),而是執行觸發後的語句 3.行級觸發器 (FOR EACH ROW) 在SQL ...
  • 如果你的應用需要一個持久的WiFi長連接,你可以通過設置應用的Info.plist文件中的UIRequiresPersistentWiFi配置項的Boolean值來達到目的。如果這個配置項的值為YES,操作系統會在你的應用啟動的時候打開一個WiFi連接,並且在你的應用運行期間一直保持這個連接處於打開 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...