一.界面搭建 1.確定開發模式 如果界面是固定的,可以用xib 界面的一些內容不固定,就用純代碼 cell用什麼方式去開發(我們採用純代碼和xib結合的方式) 2.劃分層次結構 2.1 怎麼劃分? 按照功能劃分 1.確定開發模式 如果界面是固定的,可以用xib 界面的一些內容不固定,就用純代碼 ce ...
一.界面搭建 1.確定開發模式 如果界面是固定的,可以用xib 界面的一些內容不固定,就用純代碼 cell用什麼方式去開發(我們採用純代碼和xib結合的方式) 2.劃分層次結構 2.1 怎麼劃分? 按照功能劃分 按照隱藏效果:在某些條件下,一些控制項要一起隱藏,就可以放在同一模塊中(前提是這些控制項集中在一起) 2.2 分析界面發現cell的middleView和commentView不確定要不要顯示 所以,cell採用純代碼方法搭建 3.自定義cell 3.1在創建cell的時候,就把所有可能顯示的模塊全部添加到cell上 把所有可能出現的模塊(控制項)全部添加到cell裡面,然後根據需求再決定某些模塊(控制項)是顯示還是隱藏 3.2根據伺服器數據,決定某些模塊是否隱藏 3.3在哪裡創建cell? 採用註冊的方法,底層會自動調用initWithStyle方法來創建cell 4.一個模塊一個模塊去搭建 4.1把cell分解為四個模塊,如上圖 4.2先把一個模塊所有的內容(搭建界面)和業務邏輯處理完,在去處理下一個模塊 4.3模塊的處理方式:先搭建界面,再處理界面業務邏輯 4.4優點:業務邏輯清晰,不容易混淆 二.topView模塊開發 1.xib搭建界面 1.1分析界面有哪些控制項來搭建 1.2自定義uiview並創建xib,描述好界面後,把界面添加到cell裡面 2.請求數據 2.1 查看介面文檔,使用afn發送網路請求 2.2網路請求成功時,把數據轉換成模型 2.3在模型中定義屬性(先自定義模型) 查看界面需要使用哪些數據,就找到定義數據的屬性定義到模型中 2.3自定義視圖模型,視圖模型包含模型(就是在視圖模型中定義一個模型的屬性) 2.4遍歷模型,全部轉換為視圖模型 創建視圖模型對象 用視圖模型的模型屬性來接收模型 把視圖模型保存到數組中 3.在視圖模型中計算cell子控制項的frame和高度 3.1什麼時候計算的 在模型轉視圖模型的時候計算的 3.2在哪裡計算的? 重寫視圖模型的模型屬性的set方法,在方法裡面計算cell的frame和高度,並定義屬性保存起來 因為,在模型轉視圖模型的時候,會把模型傳給視圖模型的模型屬性,底層會觸發視圖模型的模型屬性set方法,這個時候就去計算了 3.3 cell的高度計算 cell的高度就是Y軸方向最後一個控制項的最大Y值 4.展示數據 4.1怎麼展示? 在自定義cell裡面定義視圖模型屬性 創建cell之後,從數組中取出對應的視圖模型,給cell的視圖模型屬性賦值(觸發視圖模型的set方法) 4.2模型怎麼接收數據的? 在cell視圖模型屬性的set方法裡面,設置cell的frame和cell的高度(直接從視圖模型中去) 在把視圖模型的數據直接賦值給模型(觸發模型的set方法) 重寫模型的set方法,然後給界面的UI元素賦值,這樣就能在界面上看到數據了 5.註意點 5.1 cell會迴圈利用,設置某項屬性後,一定要記得還原 5.2 運行會報一些莫名其妙的約束衝突 是系統的自動拉伸約束有衝突,取消掉就可以了 三.middleView模塊搭建 middleView模塊的樣式也分很多種 我們可以利用xib搭建不同樣式的middleView,然後根據伺服器數據決定顯示哪種樣式的middleView 註意:一定要把其它樣式的middleView隱藏,還需要在其它地方還原,防止迴圈引用 根據需求我們可以把middleView分為四種樣式: 1.textView樣式 也就是沒有middleView,這種樣式只要不顯示middleView就可以了(把pictureView,videoView,voiceView隱藏) 也不需要計算frame的高度了 2.pictureView樣式
2.1 分析界面有哪些控制項組成, 界面怎麼搭建? 載入圖片的時候:有一個gif圖標,用ImageView來搭建,進度條可以放在一個view裡面 文字部分:如果是圖片用ImageView,如果是文字,用label或button都行, 需要與用戶交互就用button 顯示圖片時:圖片用ImageView搭建,下麵的查看大圖用button(有圖片和文字,還有背景圖片,還要與用戶交互,只能用button) 由於界面是固定的,可以採用xib來搭建 2.2 把pictureView添加到cel裡面 2.3 請求數據 2.4 在視圖模型中計算cell子控制項的frame和高度 2.4.1首先判斷數據是什麼類型的 返回的類型是NSInther,可讀性太差,可以定義枚舉來替代,可讀性就很好
1 typedef enum : NSUInteger { 2 XTThemeItemTypeAll = 1, 3 XTThemeItemTypeVideo = 41, 4 XTThemeItemTypeVoice = 31, 5 XTThemeItemTypePicture = 10, 6 XTThemeItemTypeText = 29 7 } XTThemeItemType;
註意:定義枚舉的快捷鍵是:enum
2.4.2 如果是text類型的就不需要計算了 2.4.3 如果圖片實際高度太高,我們就在模型裡面定義一個屬性來記錄是否是大圖 2.4.4 給大圖設置一個固定高度,不需要把大圖全部展示出來了
1 // middleView:一樣計算方式 2 // 不是段子的時候,才需要計算中間View的Frame 3 if (item.type != XMGThemeItemTypeText) { 4 CGFloat middleW = textW; 5 CGFloat middleH = middleW / item.width * item.height; 6 if (middleH > XTScreenH) { // 大圖 7 middleH = 300; 8 item.is_bigPicture = YES; 9 } 10 CGFloat middleX = margin; 11 CGFloat middleY = _cellH; 12 _middleViewFrame = CGRectMake(middleX, middleY, middleW, middleH); 13 _cellH = CGRectGetMaxY(_middleViewFrame) + margin; 14 }
2.5 運行發現,如果是大圖,圖片就被壓縮了,很難看,怎麼解決? ImageView預設是圖片填充的,就是把圖片拉伸或壓縮成整個ImageView的大小 設置ImageView的內容模式,不讓它壓縮 UIViewContentModeTop 2.6 設置內容模式,發現雖然圖片不被壓縮,但是圖片不能填充ImageView(兩邊是空的) 怎麼解決? UIViewContentModeTop預設是圖片上面顯示到ImageView的頂部,但是不會進行拉伸或壓縮 我們需要先對圖片進行拉伸或壓縮處理,然後再設置 UIViewContentModeTop 就可以了 2.7 怎麼對圖片進行拉伸或壓縮處理? 可以用繪圖,生成一張新的拉伸或壓縮好的圖片 2.8 怎麼繪圖? 2.8.1 開啟圖形上下文 2.8.2 繪製圖片 2.8.3 獲取新的圖片 2.8.4 關閉圖形上下文 2.9 對圖片處理進行性能優化 2.9.1 每次設置圖片,都要進行繪圖,有可能重覆繪圖,性能不好,怎麼優化? 把處理好的圖片緩存到磁碟(沙盒)裡面,下次再設置這張圖片時,直接從磁碟取 2.9.2 怎麼對圖片緩存處理? 自己寫方法太麻煩, SDImageCache.h內部有方法緩存圖片,直接調用它的方法來進行緩存
1 [[SDImageCache sharedImageCache] storeImage:image forKey:item.image0]; 2 註意:要到入頭文件: #import <SDImageCache.h>
2.9.3 怎麼從磁碟中去圖片? 同樣也是調用SDImageCache.h方法來取
UIImage *image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.image0];
註意:key值就是圖片的url
2.10 剛開始載入圖片時,進度條怎麼設置? 2.10.1 需要設置一個功能模塊的時候,我們要先去找有沒有做該功能模塊的框架,有就直接拿來用 2.10.2 沒有的話,就找一個功能差不多的模塊來修改一下 2.10.3 怎麼去查找一個框架?
1 - (void)awakeFromNib 2 { 3 _progressView.progressLabel.textColor = [UIColor whiteColor]; 4 _progressView.progressTintColor = [UIColor whiteColor]; 5 _progressView.roundedCorners = 10; 6 7 _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",0.0 * 100]; 8 _progressView.progress = 0; 9 } 10 11 - (void)setItem:(XMGThemeItem *)item 12 { 13 _item = item; 14 15 // 設置圖片 16 UIImage *image = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.image0]; 17 if (image) { 如果有圖片直接設置,並把進度設為100% 18 _imageView.image = image; 19 _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",1.0 * 100]; 20 _progressView.progress = 1; 21 } else { 如果沒有圖片,就先把進度設置為0 ,再去下載圖片 22 _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",0.0 * 100]; 23 _progressView.progress = 0; 24 // 下載網路圖片 25 [_imageView sd_setImageWithURL:[NSURL URLWithString:item.image0] placeholderImage:nil options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) { 26 進度就為已下載的文件大小 / 總文件大小 27 CGFloat progress = 1.0 * receivedSize / expectedSize; 28 運行發現,進度有時候為-0,列印發現總文件大小該開始為-0 當為-0 的時候就返回 29 註意:該block會頻換調用,所以 returen一次沒關係 30 if (expectedSize < 0) return ; 31 _progressView.progressLabel.text = [NSString stringWithFormat:@"%.1f%%",progress * 100]; 32 _progressView.progress = progress; 33 34 } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 35 36 if (!item.is_bigPicture) return ; 37 38 // 生成一個新拉伸好圖片 39 CGFloat w = XMGScreenW - 20; 40 CGFloat h = w / item.width * item.height; 41 42 // 開啟圖形上下文 43 UIGraphicsBeginImageContextWithOptions(CGSizeMake(w, h), NO, 0); 44 // 繪圖 45 [image drawInRect:CGRectMake(0, 0, w, h)]; 46 // 獲取上下文圖片 47 image = UIGraphicsGetImageFromCurrentImageContext(); 48 // 保存圖片到沙盒 49 [[SDImageCache sharedImageCache] storeImage:image forKey:item.image0]; 50 // 關閉上下文 51 UIGraphicsEndImageContext(); 52 53 _imageView.image = image; 54 }]; 55 } 56 根據伺服器數據,決定gif圖片是否顯示 57 _gifView.hidden = !item.is_gif; 58 根據自己判斷保存的屬性,來決定顯示大圖按鈕是否顯示 59 _seeBigButton.hidden = !item.is_bigPicture; 60 61 if (item.is_bigPicture) { 62 _imageView.contentMode = UIViewContentModeTop; 63 _imageView.clipsToBounds = YES; 64 } else { 65 _imageView.contentMode = UIViewContentModeScaleToFill; 66 _imageView.clipsToBounds = NO; 67 } 68 }
3.videoView樣式 和 voiceView樣式
3.1 由於這兩個模塊基本相同,處理方法也差不多 註意:把搭建好的xib的view拷貝到另一個xib裡面的時候,會把對應的連線也拷過去,一定要先刪除這些連線,再繼續使用
3.2 根據類型,只需要設置中間按鈕的圖片就可以了 3.3 xib搭建界面,並把界面添加到cell裡面 3.4 請求數據 3.5 在視圖模型中計算cell子控制項的frame和高度 3.6 展示數據 3.6.1 在videoView或voiceView的模型里設置數據的時候,要對數據進行處理 3.6.2 為什麼要處理? 伺服器返回的時間數據是以秒為單位的,需求以 00:00 來顯示 3.6.3 怎麼處理?
1 NSInteger minute = item.voicetime / 60; 2 NSInteger second = item.voicetime % 60; 3 self.timeLabel.text = [NSString stringWithFormat:@"%02ld:%02ld",minute,second];
4 在cell模型屬性的set方法裡面統一設置middleView各個模塊的frame的是否隱藏
1 // middleView 2 if (vm.item.type == XMGThemeItemTypePicture) { // 圖片 3 _pictureView.hidden = NO; 4 _videoView.hidden = YES; 5 _voiceView.hidden = YES; 6 7 _pictureView.item = vm.item; 8 _pictureView.frame = vm.middleViewFrame; 9 10 } else if (vm.item.type == XMGThemeItemTypeVideo) { // 視頻 11 _pictureView.hidden = YES; 12 _videoView.hidden = NO; 13 _voiceView.hidden = YES; 14 15 _videoView.item = vm.item; 16 _videoView.frame = vm.middleViewFrame; 17 } else if (vm.item.type == XMGThemeItemTypeVoice) { // 音頻 18 _pictureView.hidden = YES; 19 _videoView.hidden = YES; 20 _voiceView.hidden = NO; 21 22 _voiceView.item = vm.item; 23 _voiceView.frame = vm.middleViewFrame; 24 25 } else { 26 _voiceView.hidden = YES; 27 _pictureView.hidden = YES; 28 _videoView.hidden = YES; 29 }