关于UITableView截屏功能的实现

公司项目需要对一个以TableView为主体的画面进行拼接截屏分享。
原画面:
原画面

分享图片效果1:
分享图片

需要将tableHeaderView中地图和列表内容以及列表本身拿出来,拼接上头部和底部。

技术点一:对视图截屏
利用CoreGraphic实现视图到图片的变换。代码如下:

func imageFromView(_ view: UIView) -> UIImage? {
    var rect = view.frame
    if self.isKind(of: UIScrollView.self) {
        rect.size = (view as! UIScrollView).contentSize
    }
    UIGraphicsBeginImageContext(rect.size)
    if let context = UIGraphicsGetCurrentContext() {
        view.layer.render(in: context)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
    return nil
}

从上面的代码克制,这是通过Core Graphics的上下文环境对层的渲染实现的。在视图被draw出来之前是转化出来的是空的图层。那么问题来了,用户点击分享按钮的时候,UITableView可能并未全部显示,这时候截屏得到的就只是当前画面显示出来的部分。如何解决这个问题,请看技术点二。

技术点二:在进入画面时就显示UITableView全部的cell。
我曾经试过在画面加载完成后通过改变UITableView的contentOffset让其滑到最下方,然后再滑动回顶部,发现这种方式无效,还影响了前画面切换到当前画面的流畅性。
我又尝试过另外增加一个UITableView,专门负责分享功能,其加载的数据同显示的一样,只是在视图层次的最下方。但是发现由于这个新增加的视图在最下方,它的cellForRow等函数始终没有被调用,说明它没有被显示。
我发现方案只有这一个:在UITableView的外面套一个UIScrollView,在UITableView加载数据(reloadData)完成后,将它的Frame.size改为其ContentSize,让它撑开。这样所有的cell都会显示出来。代码如下:

设置约束让self.scrollView可以自动计算contentSize,
scrollView包含一个tableView和一个底部bottomView:

self.scrollView.snp.makeConstraints { (make) in
    make.top.equalTo(self.view).offset(kViewTopOffset)
    make.left.right.bottom.equalTo(self.view)
}
self.tableView.snp.makeConstraints { (make) in
    make.top.left.right.equalTo(self.scrollView)
    make.width.equalTo(kScreenWidth)
    make.height.equalTo(kScreenHeight - kViewTopOffset)
}
self.bottomView.snp.makeConstraints { (make) in
    make.top.equalTo(self.tableView.snp.bottom)
    make.left.right.equalTo(self.scrollView)
    make.height.equalTo(100)
    make.bottom.equalTo(self.scrollView)
}

取得数据后,更新tableView的高度

self.tableView.reloadData()
let newHeight = self.tableView.contentSize.height
    self.tableView.snp.updateConstraints { (make) in
    make.height.equalTo(newHeight)
}

但是这时候发现tableView的高度并不能更新为contentSize,而是比contentSize小的一个值。这是因为在iOS7之后,为了UITableView提高滑动的流畅性,引入了estimatedRowHeight的属性,其默认值是44,在reloadData之后得到的ContentSize = cell的个数 * estimatedRowHeight + sectionheader的个数 * estimatedSectionHeaderHeight + sectionFooter的个数 * estimatedSectionFooterHeight得到的。
为了得到准确的contentSize,你还需要在初始化tableview时加上这个:

self.tableView.estimatedRowHeight = 0
self.tableView.estimatedSectionHeaderHeight = 0
self.tableView.estimatedSectionFooterHeight = 0

这篇blog里介绍了一个挺牛的对tableView变高cell的扩展,还支持通过RunLoop进行高度预缓存,可以学习下:
http://blog.sina.com.cn/s/blog_8d1bc23f0102wkp1.html

技术点三:Core Graphics截屏清晰度优化
相关优化技术我会另外写另一篇文章

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值