[摘要]本文是對不等高cell搭建(二)的講解,對學習IOS蘋果軟件開發有所幫助,與大家分享。
一.commentView模塊搭建
commentView樣式分為兩種
1.xib搭建界面
1.1 因為評論的樣式大體上一樣,我們可以用同一個xib來處理
1.2 最熱評論 用一個label來搭建
1.3 下面的內容不一樣
1.3.1 文本樣式的評論,下面也用一個label搭建就可以了
label約束設置為左右和上面固定間距,這樣,高度會隨著內容縮放,前提是設置label為0行
1.3.2 聲音樣式評論
聲音樣式的評論.高度是固定的
先添加一個view在文本評論的位置(根據數據再決定到時候哪種樣式的評論顯示,上面的部分是一樣的)
再往view裡面添加一個label 和 button 就行了
注意:button的圖片和文字有間距 只需要設置內部子控件的內邊距就行了
如果label下面對view有約束,button下面就不要對view設置約束了 會有沖突, 總之,設置其中一個,另一個就不要設置了
2.請求數據
2.1 在設置模型屬性的時候,我們要對數據進行處理
2.2 從上圖中可以看到,我們需要拿到username 首先要拿到top_cmt這個數組,然後再拿到 user字典
2.3 我們習慣都是面向模型開發,所以我們拿到 top_cmt 數組的第一個元素(字典) 轉為模型
2.4 然後取出字典中的user字典,在轉為另一個模型
2.5 那麼我們就需要先自定義兩個模型
2.6 我們最好在最外層模型中定義一個模型屬性,來保存內層的一個模型(item0 也是就是評論模型) 為什麼?
在取內層模型屬性的時候,會因為層級太深,需要寫很長一段代碼
進行這樣的優化後,取內層模型屬性的時候,就方便很多
2.7 怎麼把模型中的數組屬性裡面的字典轉換為 模型中的一個屬性
重寫數組元素的set方法 只要拿到數組中的字典元素,給模型中的這個屬性賦值
為了嚴謹,要判斷數組是否為空
// 給模型的top_cmt屬性賦值調用
- (void)setTop_cmt:(NSArray *)top_cmt
{
_top_cmt = top_cmt;
if (top_cmt.count) {
_commentItem = top_cmt.firstObject;
}
}
3.怎麼在外層模型裡面,把模型中的數組屬性中的字典(或字典屬性)轉成模型?
有兩種方法來轉
3.1第一種方法 ,自己手動利用MJ框架來轉
3.2第二種方法,讓MJ框架自動幫我們轉,(前提是MJ框架知道模型中屬性要轉成哪種類型的模型)
3.3 MJ框架怎麼自動幫我們轉內層模型?
MJExtension:如果模型中有模型,MJExtension會自動幫你轉換好
@property (nonatomic, strong) XTUserItem *user;
因為我們在定義這個字典的時候,就告訴MJ框架,要把字典轉為哪種類型的模型
MJExtension:如果模型中有數組,數組中又是字典,MJExtension不會自動幫你轉
MJExtension可以把數組中字典轉模型 ,但是需要告訴他要把數組中的字典轉為哪種類型的模型
3.4 怎麼告訴MJ把數組中的字典轉為哪種類型的模型
// key:哪個數組需要轉換
+ (NSDictionary *)mj_objectClassInArray
{
return @{@"top_cmt":@"XTCommentItem"};
}
3.5 MJExtension底層實現
3.5.1 MJ底層是利用KVC對模型進行賦值的
遍歷模型中的key, 然後去字典中查找對應的value對key賦值
3.5.2 利用kvc賦值,模型中可以沒有字典中的某些key值, 但模型中的key 在字典中一定要有對應的value,否則會報錯
MJ框架不存在這個問題,
kvc底層實現: http://www.jianshu.com/p/45cbd324ea65
KVC是通過[item setValuesForKeysWithDictionary:dict]這個方法,將字典轉為模型
setValuesForKeysWithDictionary:底層實現
便利字典當中的所有Key Value值.給對應的key,value賦值
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
給對應的key,value賦值
setValuesForKeysWithDictionary:會調用setValue:forKeyPath:
[item setValue:obj forKeyPath:key];
}];
setValue:forKeyPath:的底層實現:
setValue: forKeyPath:
1.根據key值與當前的屬性進行對比,先去看有沒有與key值相同的set方法.如果有,就調用set方法.
2.如果沒有,再去對比,有沒有跟key值相同的成員屬性,如果有,就直接進行賦值.
3.如果沒有,再去對比,有沒有跟key值相同的而且帶有下劃線的成員屬性,如果有,就直接進行賦值.
4.如果還沒有,會調用setValue:(id)value forUndefinedKey:
5.如果沒有實現,直接報錯.
3.5.3 kvc要求,在模型中定義的key值得數據類型 一定要跟字典中key對應的value的值的數據類型相同,否則會報錯
3.5.4 MJ框架,能夠把一些key值的數據類型自動轉換為和字典中key對應的value的數據類型(前提是,這個兩種數據類型能相互轉換)
4.在視圖模型中計算cell子控件的frame和高度
if (item.commentItem) { // 先判斷有沒有最熱評論,有評論才需要計算
CGFloat commentH = 42; 聲音評論,高度是確定的
注意點:以後只要判斷字符串有沒有內容,用長度
if (item.commentItem.content.length) { // 有內容,就是文本評論
根據文字的高度來計算評論的高度
NSString *totalStr = [NSString stringWithFormat:@"%@:%@",item.commentItem.user.username,item.commentItem.content];
textH = [totalStr sizeWithFont:[UIFont systemFontOfSize:17] constrainedToSize:CGSizeMake(textW, MAXFLOAT)].height;
commentH = 21 + textH;
}
CGFloat commentW = textW;
CGFloat commentX = margin;
CGFloat commentY = _cellH;
_commentViewFrame = CGRectMake(commentX, commentY, commentW, commentH);
_cellH = CGRectGetMaxY(_commentViewFrame) + margin;
}
5.展示數據
可以根據top_cmt數組的元素個數來判斷commentView是否顯示 或者根據這個數組中的元素轉換的模型是否存在判斷
二.bottomView模塊搭建
此界面搭建相對來說比較簡單,就不做具體介紹了
1.xib搭建界面
2.請求數據
2.1 查看接口文檔,使用afn發送網絡請求
2.2網絡請求成功時,把數據轉換成模型
2.3在模型中定義屬性(先自定義模型)
查看界面需要使用哪些數據,就找到定義數據的屬性定義到模型中
2.3自定義視圖模型,視圖模型包含模型(就是在視圖模型中定義一個模型的屬性)
2.4遍歷模型,全部轉換為視圖模型
創建視圖模型對象
用視圖模型的模型屬性來接收模型
把視圖模型保存到數組中
3.在視圖模型中計算cell子控件的frame和高度
高度給一個固定值就行了,cell的高度就是Y軸方向最後一個控件的最大Y值
4.展示數據
4.1展示數據的方法都一樣,這裡主要是對數據進行一些處理
4.2當評論或贊的數字超過一萬的時候要進行處理
4.2.1 超過一萬,讓總數除以一萬,得到的數字保留一位小數,顯示xx.x萬
4.2.2 如果總數為0的話,顯示在界面上,效果很差,我們要進行一些處理
如果數據為0, 我們就在界面顯示占位文字
處理數據原碼
- (void)setItem:(XTThemeItem *)item
{
[super setItem:item];
[self setButton:_dingView count:item.ding title:@"贊"];
[self setButton:_caiView count:item.cai title:@"踩"];
[self setButton:_shareView count:item.repost title:@"轉發"];
[self setButton:_commentView count:item.comment title:@"評論"];
}
- (void)setButton:(UIButton *)button count:(NSInteger)count title:(NSString *)title
{
如何抽取一個方法:先把要抽取成方法的源代碼拷貝過來,缺什麼補什麼就行了,需要外界決定的東西,寫成參數,讓外界傳遞進來
CGFloat valueF = 0;
NSString *str = title;
if (count > 10000.0) {
valueF = count / 10000.0;
str = [NSString stringWithFormat:@"%.1f萬",valueF];
str = [str stringByReplacingOccurrencesOfString:@".0" withString:@""];
} else if (count > 0) {
str = [NSString stringWithFormat:@"%ld",count];
}
[button setTitle:str forState:UIControlStateNormal];
}
三.處理cell的外觀細節
1.cell的選中樣式很難看,我們怎麼取消?
1.1 設置cell的一個屬性就可以了
self.selectionStyle = UITableViewCellSelectionStyleNone;
1.2 在哪裡寫代碼?
在初始化cell方法裡面寫
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
2.我們想把分割線設置的寬一點,怎麼設置?
首先,我們要先取消系統的分割線
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
2.1自定義分割線
給cell的底部加一個uiview設置高度和顏色能達到分割線的效果
2.2 設置cell的frame,讓cell的高度減少一個值,減少的部分就能看到背景色,只需要設置背景色就可以達到設置分割線的目的
注意:在這裡減少的值,一定要在設置cell的高度的時候加上去,否則cell可能被壓縮
設置frame源代碼
- (void)setFrame:(CGRect)frame
{
frame.origin.y += 10;
frame.size.height -= 10;
注意:一定要調用super方法
[super setFrame:frame];
}
2.3 給cell設置背景圖片
通過 backgroundView屬性給cell設置背景圖片,只需要給cell的 backgroundView設置UIImageView就可以了
設置完發現,背景圖片邊緣有些難看,很有可能是圖片被拉伸了,我們要對圖片進行處理
設置圖片的可拉伸區域,然後再設置cell的背景圖片
設置cell背景圖片原碼
UIImage *image = [UIImage imageNamed:@"mainCellBackground"];
處理圖片:設置可拉伸區域
image = [image stretchableImageWithLeftCapWidth:image.size.width * 0.5 topCapHeight:image.size.height * 0.5];
self.backgroundView = [[UIImageView alloc] initWithImage:image];