UITableView中除了利用系統的UItableViewCell不能完成需求進行佈局時,還能夠進行自定義佈局;數組
自定義佈局分爲兩類:(1)利用代碼進行建立緩存
(2)利用xib進行實現;ide
下面對利用代碼進行建立分析:佈局
應用場景:像微博,等列表數據展現(因爲微博的每一個單元格的數據大小不一致,因此得計算每一個單元格的大小) 分析:前提是獲取列表數據,而後創建每一個單元格的模型(創建單元格模型應繼承UITableViewCell)複寫 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 此方法便可,在此方法中添加單元格所須要的各個視圖控件, 而後根據微博對象模型,肯定每一個控件的位置,並進行數據 的填充, 主要在此方法中幾個重要的方法:(特別是方法的執行順序) 1.-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 2.-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
下面以一個例子進行說明:字體
因爲本案例整個界面就是單獨的一個UITableView,故而主控制器設置成UITableViewController;這樣能夠減小不少連線問題,atom
由於UITableViewController裏面已進行關聯,且內部也開放出來了tableview;能夠直接使用spa
(1)下面是一個SLViewController.m文件代理
1 #import "SLViewController.h" 2 3 #import "SLWeiBo.h" 4 #import "SLWeiBoCell.h" 5 #import "SLWeiBoFrame.h" 6 7 @interface SLViewController () 8 9 //定義數組,保存模型數據 10 @property (nonatomic,strong)NSArray *statusFrames; 11 12 @end 13 14 @implementation SLViewController 15 16 - (void)viewDidLoad 17 { 18 [super viewDidLoad]; 19 self.tableView ; 20 } 21 22 #pragma mark -懶加載 23 -(NSArray *)statusFrames 24 { 25 if (_statusFrames==nil) { 26 //加載plist數據文件 27 NSString *fullpath=[[NSBundle mainBundle] pathForResource:@"statuses" ofType:@"plist"]; 28 NSArray *arr=[NSArray arrayWithContentsOfFile:fullpath]; 29 NSMutableArray *mutearr=[NSMutableArray arrayWithCapacity:arr.count]; 30 for (NSDictionary *dict in arr) { 31 //字典轉模型,傳進去一個字典,返回一個微博模型 32 SLWeiBo *weibo=[SLWeiBo weiBoWithDict:dict]; 33 //計算每個表格的高度並保存 34 SLWeiBoFrame *weiboframe=[[SLWeiBoFrame alloc] init]; 35 weiboframe.weibo=weibo; 36 //把Frame模型保存到數組中 37 [mutearr addObject:weiboframe]; 38 } 39 40 self.statusFrames=[mutearr mutableCopy]; 41 } 42 return _statusFrames; 43 } 44 45 #pragma mark -實現數據源方法 46 /** 47 * tableview中返回一共有多少組,有一組的話,能夠省略不寫 48 * 49 * @param tableView 50 * 51 * @return 返回有多少組 52 */ 53 -(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView 54 { 55 return 1; 56 } 57 /** 58 * tableview返回一共有多少個單元格 59 * 60 * @param tableView 61 * @param section 第幾組 62 * 63 * @return 某組有多少單元格 64 */ 65 -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 66 { 67 return self.statusFrames.count; 68 } 69 70 /** 71 * tableView返回每一個單元格的對象 72 * 73 * @param tableView 74 * @param indexPath 保存有該對象是第幾組,第幾個單元格 75 * 76 * @return 返回每一個單元格對象 77 */ 78 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 79 { 80 //1.從緩存中取數據 81 static NSString *identifier=@"status"; 82 SLWeiBoCell *cell=[tableView dequeueReusableCellWithIdentifier:identifier]; 83 //2建立表格 84 if (cell==nil) { 85 cell=[[SLWeiBoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; 86 } 87 //3設置數據 88 SLWeiBoFrame *frame=self.statusFrames[indexPath.row]; 89 cell.itemframe=frame; 90 return cell; 91 } 92 #pragma mark -實現高度的代理方法 93 /** 94 * 計算每一個單元格的高度 95 * 96 * @param tableView 97 * @param indexPath 該單元格是某組某行的單元格 98 * 99 * @return 返回該單元格的高度 100 */ 101 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 102 { 103 SLWeiBoFrame *frame=self.statusFrames[indexPath.row]; 104 return frame.cellHeight; 105 } 106 /** 107 * 設置是否顯示狀態欄 108 * 109 * @return 返回YES,不顯示,返回NO,顯示 110 */ 111 -(BOOL)prefersStatusBarHidden 112 { 113 return NO; 114 } 115 @end
(2)這個SLWeiBo.H與SLWeiBo.m Global.h文件code
第一個文件是定義一些基本屬性,用來進行字典轉換模型;並定義了兩個方法,一個是類方法,一個實例方法,在第二個文件中進行實現對象
第三個文件是對第一個和第二個文件的定義方法進行的抽取,方便重用,第三個文件利用定義宏進行代碼抽取,
1 #import "Global.h" 2 /** 3 * 建立一個微博對象,保存模型數據 4 */ 5 @interface SLWeiBo : NSObject 6 7 @property (nonatomic,copy) NSString *text;//內容 8 @property (nonatomic,copy) NSString *icon;//頭像 9 @property (nonatomic,copy) NSString *name;//暱稱 10 @property (nonatomic,copy) NSString *picture;//配圖 11 //是不是vip 12 @property (nonatomic,assign) BOOL vip; 13 14 initWeiBo(weiBo) 15 ////進行轉換的實例方法 16 //-(instancetype)initWithWeiBo:(NSDictionary *)dict; 17 //// 進行轉換的類方法 18 //+(instancetype)weiBoWithDict:(NSDictionary *)dict; 19 20 @end
1 #import "SLWeiBo.h" 2 3 @implementation SLWeiBo 4 5 //分別對類方法和實例方法進行實現 6 weiBoInitDict(weiBo); 7 //-(instancetype)initWithWeiBo:(NSDictionary *)dict; 8 //{ 9 // if (self=[super init]) { 10 // [self setValuesForKeysWithDictionary:dict]; 11 // } 12 // return self; 13 //} 14 // 15 //+(instancetype)weiBoWithDict:(NSDictionary *)dict 16 //{ 17 // return [[self alloc] initWithWeiBo:dict]; 18 //} 19 20 @end
1 #ifndef ___Global_h 2 #define ___Global_h 3 4 #define initWeiBo(name)\ 5 -(instancetype) initWithWeiBo:(NSDictionary *)dict;\ 6 +(instancetype) name##WithDict:(NSDictionary *)dict; 7 8 #define weiBoInitDict(name)\ 9 -(instancetype) initWithWeiBo:(NSDictionary *)dict;\ 10 {\ 11 if (self=[super init]) {\ 12 [self setValuesForKeysWithDictionary:dict];\ 13 }\ 14 return self;\ 15 }\ 16 +(instancetype) name##WithDict:(NSDictionary *)dict\ 17 {\ 18 return [[self alloc] initWithWeiBo:dict];\ 19 } 20 #endif
(3)SLWeiBoCell.h和SLWeiBoCell.m文件是繼承自UITableViewCell的,是對UITableViewCell進行的重寫,已到達所須要的要求界面,
並設置數據,與設置位置。
1 #import <UIKit/UIKit.h> 2 @class SLWeiBoFrame; 3 4 @interface SLWeiBoCell : UITableViewCell 5 //導入SLweiboFrame對象,保存着一個單元格里面每一個控件的位置,及weibo對象 6 @property (nonatomic,strong) SLWeiBoFrame *itemframe; 7 8 @end
1 #import "SLWeiBoCell.h" 2 3 #import "SLWeiBoFrame.h" 4 5 #define SLFontNiCheng [UIFont systemFontOfSize:15] 6 #define SLFontZhengWen [UIFont systemFontOfSize:16] 7 @interface SLWeiBoCell() 8 //頭部頭像 9 @property (nonatomic,weak) UIImageView *iconheader; 10 //暱稱 11 @property (nonatomic,weak) UILabel *nicheng; 12 //是不是vip 13 @property (nonatomic,weak) UIImageView *vip; 14 //正文顯示 15 @property (nonatomic,weak) UILabel *zhengwen; 16 //配圖顯示 17 @property (nonatomic,weak) UIImageView *peitu; 18 19 @end 20 21 @implementation SLWeiBoCell 22 23 //複寫此方法,以達到重寫UITableViewCell的目的 24 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier 25 { 26 self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 27 if (self) { 28 // 讓自定義cell和系統的cell同樣,建立出來就擁有一些子控件提供給咱們使用 29 //1.建立頭像 30 UIImageView *iconheader=[[UIImageView alloc] init]; 31 [self.contentView addSubview:iconheader]; 32 self.iconheader=iconheader; 33 //2.建立暱稱 34 UILabel *nicheng=[[UILabel alloc] init]; 35 nicheng.font=SLFontNiCheng; 36 [self.contentView addSubview:nicheng]; 37 self.nicheng=nicheng; 38 //3.建立vip 39 UIImageView *vip=[[UIImageView alloc] init]; 40 vip.image=[UIImage imageNamed:@"vip"]; 41 [self.contentView addSubview:vip]; 42 self.vip=vip; 43 //4建立正文 44 UILabel *zhengwen=[[UILabel alloc] init]; 45 //讓正文進行多行顯示 46 zhengwen.numberOfLines=0; 47 //設置正文的字體,此時的字體應該在和計算該正文的字體長寬所用字體一致, 48 zhengwen.font=SLFontZhengWen; 49 [self.contentView addSubview:zhengwen]; 50 51 self.zhengwen=zhengwen; 52 //5建立配圖 53 UIImageView *peitu=[[UIImageView alloc] init]; 54 [self.contentView addSubview:peitu]; 55 self.peitu=peitu; 56 } 57 return self; 58 } 59 -(void)setItemframe:(SLWeiBoFrame *)itemframe 60 { 61 _itemframe=itemframe; 62 //設置數據 63 [self settingData]; 64 //設置frame 65 [self settingFrame]; 66 } 67 68 -(void)settingData 69 { 70 //設置頭像 71 SLWeiBo *weibof=self.itemframe.weibo; 72 self.iconheader.image=[UIImage imageNamed:weibof.icon]; 73 //設置暱稱 74 self.nicheng.text=weibof.name; 75 //設置vip 76 if (weibof.vip) { 77 self.nicheng.textColor=[UIColor redColor]; 78 self.vip.hidden=NO; 79 }else{ 80 self.nicheng.textColor=[UIColor blackColor]; 81 self.vip.hidden=YES; 82 } 83 //設置內容 84 self.zhengwen.text=weibof.text; 85 //設置配圖 86 if (weibof.picture) { 87 self.peitu.image=[UIImage imageNamed:weibof.picture]; 88 self.peitu.hidden=NO; 89 }else{ 90 self.peitu.hidden=YES; 91 } 92 } 93 94 -(void)settingFrame 95 { 96 //1設置頭像的frame 97 self.iconheader.frame=self.itemframe.iconF; 98 //2設置暱稱的frame 99 self.nicheng.frame=self.itemframe.nichengF; 100 //3設置vip的frame 101 self.vip.frame=self.itemframe.vipF; 102 //4設置正文的frame 103 self.zhengwen.frame=self.itemframe.zhengwenF; 104 //5設置配圖的frame 105 if (self.itemframe.weibo.picture) { 106 self.peitu.frame=self.itemframe.peituF; 107 } 108 } 109 @end
(4)SLWeiBoFrame.h和SLWeiBoFrame.m 文件是爲了求行高而進行的數據抽取,即先計算出行的高,而且保存每行中控件的位置;
方便傳給cell進行利用;
1 #import "SLWeiBo.h" 2 @interface SLWeiBoFrame : NSObject 3 4 /** 5 頭像的frame 6 */ 7 @property (nonatomic,assign) CGRect iconF; 8 /** 9 暱稱的frame 10 */ 11 @property (nonatomic,assign) CGRect nichengF; 12 /** 13 vip的frame 14 */ 15 @property (nonatomic,assign) CGRect vipF; 16 /** 17 正文的frame 18 */ 19 @property (nonatomic,assign) CGRect zhengwenF; 20 /** 21 配圖的frame 22 */ 23 @property (nonatomic,assign) CGRect peituF; 24 /** 25 行高 26 */ 27 @property (nonatomic,assign) CGFloat cellHeight; 28 @property (nonatomic,strong) SLWeiBo *weibo; 29 30 @end
1 #import "SLWeiBoFrame.h" 2 #import "SLWeiBo.h" 3 #define SLFontNiCheng [UIFont systemFontOfSize:15] 4 #define SLFontZhengWen [UIFont systemFontOfSize:16] 5 @implementation SLWeiBoFrame 6 7 8 -(void)setWeibo:(SLWeiBo *)weibo 9 { 10 11 _weibo=weibo; 12 //間隙 13 CGFloat padding=10; 14 //1設置頭像的frame 15 CGFloat iconViewX=padding; 16 CGFloat iconViewY=padding; 17 CGFloat iconViewW=30; 18 CGFloat iconViewH=30; 19 self.iconF=CGRectMake(iconViewX, iconViewY, iconViewW, iconViewH); 20 21 //2設置暱稱的frame 22 CGFloat nichengX=CGRectGetMaxX(self.iconF)+padding; 23 /** 24 * attributes 告訴系統文字的大小 25 */ 26 // NSDictionary *dict=@{NSFontAttributeName:[UIFont systemFontOfSize:15]}; 27 28 // 若是未來計算的文字的範圍超出了指定的範圍,就返回的就是指定的範圍 29 //若是未來的文字範圍小於指定的範圍,就返回實際的範圍 30 CGSize maxsize=CGSizeMake(MAXFLOAT, MAXFLOAT); 31 CGSize namesize=[self sizeWithString:_weibo.name font:SLFontNiCheng maxSize:maxsize]; 32 // CGRect namesize= [_weibo.name boundingRectWithSize:maxsize options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil]; 33 34 CGFloat nichengH=namesize.height; 35 CGFloat nichengW=namesize.width; 36 37 CGFloat nichengY=(self.iconF.size.height-nichengH)*0.5+iconViewY; 38 self.nichengF=CGRectMake(nichengX , nichengY, nichengW,nichengH); 39 40 41 //3設置vip的frame 42 CGFloat vipViewX=CGRectGetMaxX(self.nichengF)+padding; 43 CGFloat vipViewY=nichengY; 44 CGFloat vipViewW=14; 45 CGFloat vipViewH=14; 46 self.vipF=CGRectMake(vipViewX, vipViewY, vipViewW, vipViewH); 47 48 49 //4設置正文的frame 50 51 CGFloat zhengwenX=iconViewX; 52 CGFloat zhengwenY=CGRectGetMaxY(self.iconF)+padding; 53 54 CGSize maxsize1=CGSizeMake(300, MAXFLOAT); 55 CGSize zhengwensize=[self sizeWithString:_weibo.text font:SLFontZhengWen maxSize:maxsize1]; 56 CGFloat zhengwenW=zhengwensize.width; 57 CGFloat zhengwenH=zhengwensize.height; 58 59 self.zhengwenF=CGRectMake(zhengwenX, zhengwenY, zhengwenW, zhengwenH); 60 //5設置配圖的frame 61 // CGFloat cellHeight=0; 62 if (_weibo.picture) { 63 CGFloat peituX=iconViewX; 64 CGFloat peituY=CGRectGetMaxY(self.zhengwenF)+padding; 65 CGFloat peituW=100; 66 CGFloat peituH=100; 67 self.peituF=CGRectMake(peituX, peituY, peituW, peituH); 68 self.cellHeight=CGRectGetMaxY(self.peituF)+padding; 69 }else 70 { 71 //無配圖的狀況下的行高 72 self.cellHeight=CGRectGetMaxY(self.zhengwenF)+padding; 73 } 74 } 75 76 /** 77 * 計算文本的寬高 78 * 79 * @param str 文本顯示 80 * @param font 文本顯示的字體 81 * @param maxSize 文本顯示的此存 82 * 83 * @return 84 */ 85 -(CGSize)sizeWithString:(NSString *)str font:(UIFont *)font maxSize:(CGSize)maxSize 86 { 87 NSDictionary *dict=@{NSFontAttributeName: font}; 88 CGSize nasize=[str boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:dict context:nil].size; 89 return nasize; 90 } 91 92 @end
最終實現效果圖以下:
以上方法,便是利用代碼進行對UITableViewCell進行的重寫,下一講講解關於
利用xib建立重用的單元格對象。