iOS 截取长图及分享、拼接图片、优化内存问题

2018-06-01  本文已影响3250人  L一N

我们先来看看分享的长图效果及高度:


屏幕快照 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。
希望有更好的方法的朋友可以留言分享出来。

上一篇下一篇

猜你喜欢

热点阅读