雖然在UITableView中可以直接拖控件的方式進行添加cell,但是這種方式有一個致命的缺點,那就是cell是固定的,而且cell的高度難以更改。在實際的開發中並不能滿足我們的需求。比如以下:
wps_clip_image-16424 在這個TableView中每一個cell中有一個顯示時間的label,一個顯示內容的button,一個顯示頭像的imageView 並且由於聊天內容的多少 每一個cell的高度都是動態改變的,顯然系統提供的cell並不能滿足需求! 與此類似的還有微博手機客戶端,糗事百科客戶端等等 以下是搭建此類UI界面的大概步驟,不涉及網絡功能,和存儲功能,所有的數據信息用plist文件配置。 wps_clip_image-8661 1.1 根據數據建立數據模型 @interface CLWeiBo : NSObject @property (nonatomic,copy) NSString *text;//正文 @property (nonatomic,copy) NSString *icon;//頭像 @property (nonatomic,copy) NSString *name;//昵稱 @property (nonatomic,copy) NSString *picture;//圖片 @property (nonatomic,assign,getter = isVip) BOOL *vip;//VIP 1.2 提供兩個初始化方法 - (instancetype) initWithDict: (NSDictionary *)dict;//對象方法 + (instancetype) weiboWithDict: (NSDictionary *)dict;//類方法 方法內部實現就不再贅述了! 2.1 根據數據模型建立frame模型 之所以建立frame模型,是為了封裝計算cell內各個控件位置的過程。這體現了OOP的編程思想! 在Frame模型中,各個控件的Frame會根據傳遞過來的數據模型進行計算設置,所以Frame模型中必須有一個數據模型屬性,且計算各個控件的frame的過程應該放在模型數據屬性的set方法中,並且在這裡計算出cell的高度 復制代碼 @interface CLWeiBoFrame : NSObject /** * 頭像的Frame 如果成員變量只允許類本身修改,應該把它聲明成readonly,體現良好的編碼習慣。 */ @property (nonatomic, assign, readonly)CGRect iconF; /** * 正文的frame */ @property (nonatomic, assign, readonly)CGRect textF; /** * VIP圖標的frame */ @property (nonatomic, assign, readonly)CGRect vipF; /** * 昵稱的Frame */ @property (nonatomic, assign, readonly)CGRect nameF; /** * 圖片的Frame */ @property (nonatomic, assign, readonly)CGRectpictureF; /** * 數據模型 */ @property (nonatomic, strong) CLWeiBo *weibo; /** * cell的高度 */ @property (nonatomic, assign, readonly) CGFloat cellHeight; @end 復制代碼 3.1 新建CLWeiBocell並且繼承自UITableViewCell 有frame模型類型的成員屬性,用來對cell內的各個控件設置frame 以及數據 因為frame模型中有一個數據模型 所以這裡無需再引入數據模型 @property (nonatomic, strong) CLWeiBoFrame *weiboFrame; 並且提供一個類方法,外界調用建立cell的接口,需要傳入參數tableView 。傳入tableView參數是為了能夠取得tableView內的cell隊列循環利用cell + (instancetype)cellWithTableView:(UITableView*)tableView { static NSString *ID = @"weibo"; CLWeiBoCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[CLWeiBoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } return cell; } 3.2 重寫系統的cell的構造方法 在初始化cell對象的時候調用,在這個方法中添加cell的子控件 復制代碼 -(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:stylereuseIdentifier:reuseIdentifier]; if (self) { // 1.頭像 //在這裡只是聲明並添加控件 控件的frame設置以及數據的設置放在frame模型屬性的set方法中 在拿到frame模型數據後同時設置cell內子控件的frame和數據 UIImageView *iconView = [[UIImageView alloc]init]; [self.contentView addSubview:iconView]; self.iconView = iconView; // 2.昵稱 UILabel *nameView = [[UILabel alloc] init]; nameView.font = MJNameFont; [self.contentView addSubview:nameView]; self.nameView = nameView; // 3.會員圖標 UIImageView *vipView = [[UIImageView alloc]init]; vipView.image = [UIImage imageNamed:@"vip"]; [self.contentView addSubview:vipView]; self.vipView = vipView; // 4.正文 UILabel *textView = [[UILabel alloc] init]; textView.numberOfLines = 0; textView.font = MJTextFont; [self.contentView addSubview:textView]; self.textView = textView; // 5.配圖 UIImageView *pictureView = [[UIImageViewalloc] init]; [self.contentView addSubview:pictureView]; self.pictureView = pictureView; } return self; } //frame模型數據 變量的set方法 在這裡接到外界的frame模型數據的同時設置frame和顯示數據 - (void) setCLWeiBoFrame:(MJStatusFrame *)statusFrame { _statusFrame = statusFrame; // 1.設置數據 [self settingData]; // 2.設置frame [self settingFrame]; } 復制代碼 4.新建控制器繼承UITableViewController 並且遵守UITableView數據源協議 4.1 在控制器中聲明frame模型屬性數組 復制代碼 /** * 存放所有cell的frame模型數據 */ @property (nonatomic, strong) NSArray *weiboFrames; //在weiboFrames的set方法中完成plist文件中的字典數據向模型數據轉換的過程 - (NSArray *)statusFrames { if (_weiboframes == nil) { // 初始化 // 1.獲得plist的全路徑 NSString *path = [[NSBundle mainBundle]pathForResource:@"statuses.plist" ofType:nil]; // 2.加載數組 NSArray *dictArray = [NSArrayarrayWithContentsOfFile:path]; // 3.將dictArray裡面的所有字典轉成模型對象,放到新的數組中 NSMutableArray *weibosFrameArray = [NSMutableArray array]; for (NSDictionary *dict in dictArray) { // 3.1.創建CLWeiBo模型對象 CLWeiBo *weibo = [CLWeiBo weiboWithDict:dict]; // 3.2.創建CLWeiBoFrame模型對象 CLWeiBoFrame *weiboFrame = [[CLWeiBoFrame alloc] init]; weiboFrame.weibo = weibo; // 3.2.添加模型對象到數組中 [weibosFrameArray addObject:weiboFrame]; } // 4.賦值 _weiboframes = _weibosframeArray; } return _weiboframes; } 復制代碼 4.2 實現數據源方法 復制代碼 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.statusFrames.count; } - (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { // 1.創建cell MJStatusCell *cell = [MJStatusCellcellWithTableView:tableView]; // 2.在這裡已經算好了cell的高度 cell.statusFrame =self.statusFrames[indexPath.row]; // 3.返回cell return cell; } 復制代碼 4.3 實現代理方法 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { // 取出這行對應的frame模型 MJStatusFrame *statusFrame =self.statusFrames[indexPath.row]; return statusFrame.cellHeight; }