效果圖:
分析:從plist文件中讀取數據源,plist最外層是一個Array,Array中存放的是字典,每個字典存放的key值並不完全相同。
一、單元格復用問題
1、首先讀取數據源,建立數據模型,這里我只創建了一個數據模型,包含plist中所有的key值所對應的屬性。
2、創建tableView,同時定制Cell,
根據category,可以分成四種單元格,在tableView創建單元格時創建4種代碼如下:
1 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 4 CustomCell * appcustomCell = [tableView dequeueReusableCellWithIdentifier:@"appcustomCell"]; 5 6 if (!appcustomCell) { 7 appcustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"appcustomCell"]; 8 NSLog(@"appcustomCell"); 9 } 10 11 CustomCell * listcustomCell = [tableView dequeueReusableCellWithIdentifier:@"listcustomCell"]; 12 13 if (!listcustomCell) { 14 listcustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"listcustomCell"]; 15 NSLog(@"listcustomCell"); 16 } 17 18 CustomCell * origincustomCell = [tableView dequeueReusableCellWithIdentifier:@"origincustomCell"]; 19 20 if (!origincustomCell) { 21 origincustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"news"]; 22 NSLog(@"origincustomCell"); 23 } 24 25 CustomCell * largecustomCell = [tableView dequeueReusableCellWithIdentifier:@"largecustomCell"]; 26 27 if (!largecustomCell) { 28 largecustomCell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"largecustomCell"]; 29 NSLog(@"largecustomCell"); 30 } 31 32 33 34 Model *model = [_dataSource objectAtIndex:indexPath.row]; 35 36 37 if ([model.category isEqualToString:@"list"]) { 38 listcustomCell.category = model.category; 39 listcustomCell.message = model.title ; 40 41 listcustomCell.imageNames = model.pics; 42 listcustomCell.source = model.source; 43 listcustomCell.time = model.time ; 44 return listcustomCell; 45 46 47 } 48 if ([model.category isEqualToString:@"origin"]) { 49 origincustomCell.category = model.category; 50 origincustomCell.message = model.title ; 51 52 origincustomCell.picture = model.picture ; 53 origincustomCell.source = model.source; 54 return origincustomCell; 55 } 56 57 if ([model.category isEqualToString:@"large"]) { 58 largecustomCell.category = model.category; 59 largecustomCell.message = model.title ; 60 61 largecustomCell.picture = model.picture; 62 largecustomCell.source = model.source; 63 largecustomCell.time = model.time; 64 return largecustomCell; 65 } 66 67 if ([model.category isEqualToString:@"app"]) { 68 appcustomCell.category = model.category; 69 appcustomCell.message = model.title ; 70 71 appcustomCell.icon = model.icon; 72 appcustomCell.appname = model.appname; 73 return appcustomCell; 74 } 75 return nil; 76 }
上面是防止復用時出錯的辦法
二、題目的重點:Cell動態調整高度
1、動態調整單元格的高度,那么肯定要調用tableView代理的一個方法,換回單元格高度,代碼如下: 1 -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
2 { 3 //用來返回每一行的高度 4 //只有確定了數據,能才知道行的高度,所以在這先要去取得數據 5 Model * model = [_dataSource objectAtIndex:indexPath.row]; 6 //因為計算行高這個事是cell來計算的,所以還得需要創建一個cell對象 7 //為了去避免在計算行高時,開辟多個cell對象空間,造成資源的浪費 8 //所以在這里,要實現cell的復用 9 cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"xx"]; 10 if (!cell) { 11 cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"xx"]; 12 13 } 14 15 //將數據賦給cell,然后cell去計算行高 16 //這里說的計算是,數據賦值給Cell的時候,都要調用定制Cell類中的對應屬性的set方法,在set方法中返回rowHight,rowHight也是Cell的屬性
17 //這樣按照單元格中的各個控件的順序返回相應的高度,一定要注意控件的排放順序 18 cell.category = model.category; 19 cell.message = model.title ; 20 if ([model.category isEqualToString:@"list"]) { 21 cell.imageNames = model.pics; 22 cell.source = model.source; 23 cell.time = model.time ; 24 25 26 } 27 if ([model.category isEqualToString:@"origin"]) { 28 cell.picture = model.picture ; 29 cell.source = model.source; 30 } 31 32 if ([model.category isEqualToString:@"large"]) { 33 cell.picture = model.picture; 34 cell.source = model.source; 35 cell.time = model.time; 36 } 37 38 if ([model.category isEqualToString:@"app"]) { 39 cell.icon = model.icon; 40 cell.appname = model.appname; 41 42 } 43 44 45 46 47 //因為cell里賦值后可以利用賦值內容來計算出行高,所以在賦值后,直接返回行高 48 return cell.rowHeight; 49 50 51 }
2、在定制單元格中返回該控件的高度,通過重寫控件的set方法確定該控件是否顯示,代碼:
1 -(void)setSource:(NSString *)source 2 { 3 4 _source = source; 5 if (![_category isEqualToString:@"app"]) { 6 sourceLabel.hidden = NO; 7 sourceLabel.text = _source; 8 sourceLabel.frame = CGRectMake(10, _rowHeight, 100, 15); 9 }
//消息所有的工作做完后,要重新雲計算一下行高
//下面這個方法是用來取一個控件的最大y值
//這個值是從原點y坐標 + 控件高度
//實際行高等於 上個值 再加 5
10 _rowHeight = CGRectGetMaxY(sourceLabel.frame) + 5; 11 12 }
在Cell定制類中首先加一個Label控件,設置為隱藏,因為不知道這個控件是不是真的需要,所以當調用控件對應內容的set方法時時肯定要使用這個控件了,將控件隱藏屬性設置為NO,這里需要重新為控件布局。因為在這個控件之前不知道已有的控件占了多少高度,這里通過rowHight屬性獲得前面的高度,然后返回時加上自己的高度,加上5是為了調整控件之間的距離吧.
3、不得不說的是label中內容很多時怎么計算其高度,
1 -(void)setMessage:(NSString *)message 2 { 3 4 //判斷一下有沒有消息 5 if (message.length == 0) { 6 //如果沒有消息 7 messageLabel.hidden = YES; 8 _rowHeight = 60.0f; 9 return; 10 } 11 //如果有消息 12 //將參數消息賦給屬性 13 _message = message; 14 //有消息要顯示,那么就將控件顯示出來 15 messageLabel.hidden = NO; 16 //求出這條消息實際占用的高度 17 //下面這個方法用來求出消息內容實際占的size 18 // message sizeWithFont:(UIFont *) 19 CGSize size = [message boundingRectWithSize:CGSizeMake(255, 9999) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil].size; 20 //根據計算過后的消息所占的寬高,來調整messageLabel的frame 21 if ([_category isEqualToString:@"origin"]) { 22 messageLabel.frame = CGRectMake(5, 20, 180, size.height); 23 } 24 else 25 { 26 messageLabel.frame = CGRectMake(5, 5, 310, size.height); 27 } 28 29 //給消息控件賦值 30 messageLabel.text = message; 31 32 //消息所有的工作做完后,要重新雲計算一下行高 33 //下面這個方法是用來取一個控件的最大y值 34 //這個值是從原點y坐標 + 控件高度 35 //實際行高等於 上個值 再加 5 36 _rowHeight = CGRectGetMaxY(messageLabel.frame) + 5; 37 38 39 }
最重要的應該是這個方法了:
CGSize size = [message boundingRectWithSize:CGSizeMake(255, 9999) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:15]} context:nil].size;不太清除是什么意思,只知道根據message字體大小計算出了一個CGSize,
總結:前面說了要做出的效果,然后說了不同單單元格解決復用重疊的方法,最后說了自動調整高度。