iOS 截取长图及分享、拼接图片、优化内存问题
我们先来看看分享的长图效果及高度:
屏幕快照 2018-06-01 上午11.07.47.png
本文是以tableView、collectionView等scrollView的截取长图,webView的原理大致一样。
大体流程:
1、保存scrollView截取前的偏移量及Frame;
2、计算出你要截取的长图的高度及宽度,即scrollView的contentSize,将scrollView.frame设成scrollView.contentSize;
3、渲染出scrollView整体(上下文),截取当前scrollView生成Image;
4、恢复scrollView的偏移量及Frame;
5、可选步骤:将得到的长Image与其他image拼接;
6、设置友盟分享消息内容、分享;
7、渲染的内存问题的优化。
Talk is cheap. Show my code:
1、保存scrollView截取前的偏移量及Frame:
//保存scrollView当前的偏移量
CGPoint savedContentOffset = scrollView.contentOffset;
CGRect saveFrame = scrollView.frame;
2、将scrollView.frame设成scrollView.contentSize:
//将scrollView的偏移量设置为(0,0)
scrollView.contentOffset = CGPointZero;
//scrollView.frame设成scrollView.contentSize
scrollView.frame = CGRectMake(0, 0, scrollView.contentSize.width, scrollView.contentSize.height);
3、渲染出scrollView整体(上下文),截取当前scrollView生成Image:
//渲染出scrollView整体(上下文)
[scrollView.layer renderInContext: UIGraphicsGetCurrentContext()];
// scrollView.layer.contents = nil;
//截取当前上下文生成Image
UIImage*image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
4、恢复scrollView的偏移量及Frame:
scrollView.contentOffset = savedContentOffset;
scrollView.frame = saveFrame;
5、【图片拼接】
//此处以截取的长图拼接头尾视图为例:
/* Image 拼接
* masterImage 主图片
* headImage 头图片
* footImage 尾图片
*/
+ (UIImage *)addHeadImage:(UIImage *)headImage footImage:(UIImage *)footImage toMasterImage:(UIImage *)masterImage {
CGSize size;
size.width = masterImage.size.width;
CGFloat headHeight = !headImage? 0:headImage.size.height/2.0;
CGFloat footHeight = !footImage? 0:footImage.size.height/2.0;
size.height = masterImage.size.height + headHeight + footHeight;
UIGraphicsBeginImageContextWithOptions(size, YES, 0.0);
if (headImage)
[headImage drawInRect:CGRectMake(0, 0, masterImage.size.width, headHeight)];
[masterImage drawInRect:CGRectMake(0, headHeight, masterImage.size.width, masterImage.size.height)];
if (footImage)
[footImage drawInRect:CGRectMake(0, masterImage.size.height + headHeight, masterImage.size.width, footHeight)];
UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resultImage;
}
6、友盟分享代码:
//1、设置分享内容:
UMSocialMessageObject *messageObject = [UMSocialMessageObject messageObject];
//设置文本
messageObject.text = @" ";
//创建图片内容对象
UMShareImageObject *shareObject = [[UMShareImageObject alloc] init];
//如果有缩略图,则设置缩略图
shareObject.thumbImage = image;
[shareObject setShareImage:image];
//分享消息对象设置分享内容对象
messageObject.shareObject = shareObject;
int platType = 0; //0,微博
//其他分享途径:
//UMSocialPlatformType_WechatSession = 1, //微信聊天
//UMSocialPlatformType_WechatTimeLine = 2,//微信朋友圈
//UMSocialPlatformType_QQ = 4,//QQ聊天页面
//UMSocialPlatformType_Qzone = 5,//qq空间
//2、发起分享:
[[UMSocialManager defaultManager] shareToPlatform:platType messageObject:messageObject currentViewController:self.vc completion:^(id data, NSError *error) {
if (error) {
NSLog(@"************Share fail with error %@*********",error);
if (error.code == 2008){
kShowMessage(@"未安装该应用");
}else if(error.code == 2009){
kShowMessage(@"取消分享");
}else
kShowMessage(@"分享失败");
[self removeSelf];
}else
{
NSLog(@"response data is %@",data);
kShowMessage(@"分享成功");
[self removeSelf];
}
}];
内存的优化问题:
在渲染长度较长的scrollView [6Plus:长度>大约20000像素] 时
使用[scrollView.layer renderInContext: UIGraphicsGetCurrentContext()];方法把view绘到画布上,功能实现后检测内存使用情况,发现这个方法会导致内存使用直线上升,然后崩溃闪退。
一、baidu的解决办法基本大致一样:
//实测感觉作用不大,但还是贴上供参考
1、将renderInContext 替换用:drawViewHierarchyInRect: afterScreenUpdates;
2、使用AutoReleasePool.
二、研究了一下:
在[view.layer renderInContext:context]之后加上一句:view.layer.contents = nil; 渲染的内存会及时释放,截取长度不过长的的图片时观察内存下降效果尤为明显。据stackoverflow里说这样是用来清除 layer绘制过后产生的缓存。
但是 ,即便如此,在较老旧的设备中:6s之前,依然会因为运行内存不足以支撑较大尺寸的View渲染而导致应用crash掉。
有一个大体的思路,抛转引玉一下,
循环体里把要截图的scrollView分成多个等份,然后渲染出每一个等份,再将view.layer.contents = nil;释放等份后的内存,最后将所有等份拼接得到主Image。
希望有更好的方法的朋友可以留言分享出来。