先上效果圖
前言
之前的一個(gè)多月扑毡,在老板的淫威之下,一直都在做純h5版本的 app盛险,好在終于擺脫了他的魔爪瞄摊,可以做自己喜歡的事勋又。于是就趕緊把快要忘掉的 iOS 撿起來(lái),立個(gè)小目標(biāo)换帜,寫個(gè)小 demo
我用iPhone6楔壤,10.1系統(tǒng)真機(jī)測(cè)試,快速滑動(dòng) FPS 保持在59~60惯驼,縱享絲滑蹲嚣。gif 是用電腦錄的,模擬器配置低祟牲,所以FPS 只有不到30
基本模塊實(shí)現(xiàn)方式
數(shù)據(jù)是百思不得姐的首頁(yè)接口端铛,類似新聞首頁(yè)布局,包含視頻疲眷,長(zhǎng)圖禾蚕,動(dòng)圖,純文本等狂丝。我將它們拆分為幾個(gè)基本的模塊介紹换淆,方便各取所需
1,長(zhǎng)文本顯示几颜,UILable 高度動(dòng)態(tài)計(jì)算
UILable的基本屬性就不再介紹了倍试,需要的同學(xué)可以自行百度
Lable.text= @"你的字符串";
Lable.font= [UIFontfontWithName:@"Arial"size:16];
NSDictionary*attrs =@{NSFontAttributeName:Lable.font};
CGSizemaxSize =CGSizeMake(Width-35,MAXFLOAT);
CGSizesize = [Lable.text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrscontext:nil].size;
NSLog(@"%f ->%f",size.height,size.width);
2,長(zhǎng)圖截取蛋哭,點(diǎn)擊放大查看
截认叵啊:
試過(guò)各種辦法,比如下面這種上下文截取谆趾,裁剪躁愿,設(shè)置imageView 的 contentMode
- (UIImage *)compressImage:(UIImage *)sourceImage toTargetScale:(CGFloat)scale {
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
UIGraphicsBeginImageContext(CGSizeMake(width * scale, height * scale));
[sourceImage drawInRect:CGRectMake(0, 0, width * scale, height * scale)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
是下圖這種效果,明顯不是我想要的沪蓬,要截取長(zhǎng)圖的頭部顯示
采用下面這種方法彤钟,可以完美裁剪長(zhǎng)圖的頭部,然后加載到 imageView 上即可
UIImage*resultImage = [UIImage imageWithCGImage:CGImageCreateWithImageInRect([imageCGImage],CGRectMake(0,0,Height,Height))];
myself.contentImageView.image= resultImage;
關(guān)于 UIImage跷叉,CIImage逸雹,CGImage 三者的區(qū)別
- CIImage包含了創(chuàng)建圖片的所有必要的數(shù)據(jù),但其本身沒(méi)有渲染成圖片云挟,它代表的是圖像數(shù)據(jù)或者生成圖像數(shù)據(jù)的流程(如濾鏡)
- CGImage是基于像素的矩陣梆砸,每個(gè)點(diǎn)都對(duì)應(yīng)了圖片中點(diǎn)的像素信息
- UIImage管理圖片數(shù)據(jù),主要用來(lái)展現(xiàn)园欣,如UIImageView中帖世,控件中等,也可以用來(lái)直接在view或其他的context中繪制
點(diǎn)擊放大查看:
圖片放大查看常見(jiàn)的第三方庫(kù)是MWPhotoBrowser俊庇,但是 MWPhotoBrowser 這個(gè)庫(kù)有一個(gè)很大的痛點(diǎn)就是查看大圖時(shí)是以PUSH 的方式跳過(guò)去的狮暑,并不是我們常見(jiàn)的動(dòng)畫彈出的方式鸡挠,從原圖的基礎(chǔ)位置放大到全屏,下圖所示搬男。對(duì)于有強(qiáng)迫癥的我來(lái)說(shuō)果斷放棄了這個(gè)庫(kù)拣展,難道要我自己封裝一個(gè)?
但由于才疏學(xué)淺缔逛,能力有限备埃,只能站在巨人的肩膀上,想起來(lái)YYKit的 demo 里實(shí)現(xiàn)了相似的功能褐奴,于是就去扒了源碼按脚。用法如下:
首先將上圖的兩個(gè)類拖入自己的項(xiàng)目
然后在imageView的點(diǎn)擊事件里執(zhí)行如下代碼
YYPhotoGroupItem*item = [YYPhotoGroupItemnew];
item.thumbView =_contentImageView;
item.largeImageURL= [NSURLURLWithString:imageURL];
YYPhotoGroupView*view = [[YYPhotoGroupViewalloc]initWithGroupItems:@[item]];
UIView*toView= [UIApplicationsharedApplication].keyWindow.rootViewController.view;
[viewpresentFromImageView : _contentImageView toContainer : toView animated : YEScompletion:nil];
注意:
1,我demo 接口只有一張圖敦冬,所以此處是單圖查看辅搬,多張圖傳item 的數(shù)組
2,YYPhotoGroupView 類里并未實(shí)現(xiàn)長(zhǎng)按圖片選擇保持到相冊(cè)功能脖旱,需要更改此類里長(zhǎng)按手勢(shì)觸發(fā)的方法代碼(大概在760行)
UIActivityViewController *activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:@[imageItem] applicationActivities:nil];
UIActivityViewControllerCompletionWithItemsHandler myblock = ^(NSString *activityType,BOOL completed,NSArray *returnedItems,NSError *activityError){
if ([activityType isEqualToString:@"com.apple.UIKit.activity.SaveToCameraRoll"]) {
MBProgressHUD *hub = [MBProgressHUD showHUDAddedTo:toVC.view animated:YES];
hub.mode = MBProgressHUDModeCustomView;
if (completed) {
hub.labelText = @"保存成功";
}else{
hub.labelText = @"保存失敗";
}
hub.removeFromSuperViewOnHide = YES;
[hub hide:YES afterDelay:1.0];
}
};
activityViewController.completionWithItemsHandler = myblock;
至此堪遂,圖片查看功能基本完成。
3萌庆,基于AVPlayer實(shí)現(xiàn)的視頻播放
之前做的視頻播放基本是下圖這個(gè)樣子溶褪,用 AVPlayer 實(shí)現(xiàn)的簡(jiǎn)單的播放器,觀察者監(jiān)聽(tīng)視頻的狀態(tài)進(jìn)行一系列操作等等践险。但是在 cell 上的視頻播放器跟單獨(dú)一個(gè)頁(yè)面的播放大不相同猿妈,前者要考慮到 cell 的復(fù)用,播放器在什么時(shí)候創(chuàng)建巍虫,同時(shí)創(chuàng)建多個(gè)低端機(jī)型內(nèi)存會(huì)不會(huì)爆掉彭则。
嘗試了多次,最后采用的的方法是首先判斷后臺(tái)接口數(shù)據(jù)的 videoUrl 字段是否有值垫言,有值就在圖片上放一個(gè)按鈕(下圖所示)贰剥,在按鈕的點(diǎn)擊方法里寫一個(gè)回調(diào)block,在tableview 的cellForRowAtIndexPath:代理方法中實(shí)現(xiàn)這個(gè) block筷频。此時(shí)才創(chuàng)建播放器。
此處推薦一個(gè)賊好用的 AVPlayer第三方庫(kù)ZFPlayer前痘,回調(diào)方法代碼如下
__weak typeof(self) myself = self;
__block MainTableCell *weakcell = _tableCell;
__block NSIndexPath *weakIndexPath = indexPath;
_tableCell.cellBlock = ^(){
if (![weakcell.modelList.videouri isEqualToString:@""]) {
ZFPlayerModel *playerModle = [[ZFPlayerModel alloc] init];
//playerModle.title = @"這是我的標(biāo)題";
playerModle.videoURL = [NSURL URLWithString:weakcell.modelList.videouri];
playerModle.placeholderImageURLString = weakcell.modelList.image0;
playerModle.tableView = myself;
playerModle.indexPath = weakIndexPath;
playerModle.fatherView = weakcell.contentImageView;
[myself.playerView playerControlView:nil playerModel:playerModle];
[myself.playerView autoPlayTheVideo];
}
};
里面用到的playerView 采用懶加載方式創(chuàng)建
- (ZFPlayerView *)playerView {
if (!_playerView) {
_playerView = [ZFPlayerView sharedPlayerView];
//_playerView.delegate = self;
// 當(dāng)cell播放視頻由全屏變?yōu)樾∑習(xí)r候凛捏,不回到中間位置
_playerView.cellPlayerOnCenter = NO;
// 當(dāng)cell劃出屏幕的時(shí)候停止播放
//_playerView.stopPlayWhileCellNotVisable = YES;
//(可選設(shè)置)可以設(shè)置視頻的填充模式,默認(rèn)為(等比例填充芹缔,直到一個(gè)維度到達(dá)區(qū)域邊界)
// _playerView.playerLayerGravity = ZFPlayerLayerGravityResizeAspect;
// 靜音
// _playerView.mute = YES;
}
return _playerView;
}
至此三個(gè)基本功能點(diǎn)基本完成坯癣,還有幾個(gè)小問(wèn)題尚待優(yōu)化,希望有經(jīng)驗(yàn)的老哥指點(diǎn)一二
- cell 的高度我采用的是contentLable 的高度 + 圖片的高度約束值 + 頭像時(shí)間等 lable 的高度最欠,基本能滿足我的需求但是肯定不是最好的辦法
- 自定義cell 類里大量的 if 判斷示罗,根據(jù)接口數(shù)據(jù)類型惩猫,無(wú)圖片的隱藏圖片 imageView,有圖片的根據(jù)圖片尺寸大小動(dòng)態(tài)改變 imageView 的約束值等
基本上就是這么多蚜点,時(shí)間倉(cāng)促轧房,技術(shù)有限,還請(qǐng)多多指正绍绘。