我需要制作一个快速更新 UIImage 的功能,一开始使用 UIImageView 来显示图片,所以需要频繁的调用 UIImageView.image = newImage
方法来更新图片。代码看起来像这样。
func onSomethingChanged() {
myUIImageView.image = newImage
}
这样更新图片非常的卡顿,操作和画面响应有一定的滞后,体验不好,因此考虑自己做一个 UIView 来绘制图片,看看是否可以解决。
于是自己自定义了一个 View,继承 UIView 来做,在 draw(rect:)
方法里面做文章。
首先当然是简单粗暴直接 UIImage.draw(in: bounds)
先看看效果。
var image: UIImage? {
didSet {
setNeedsDisplay()
}
}
override func draw(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
ctx.addRect(bounds)
ctx.setFillColor(UIColor.black.cgColor)
ctx.fillPath()
if var im = image {
im.draw(in: bounds)
}
}
很好,更新速度很快,是理想的效果,不过目前画面是拉伸的,同时还有锯齿。
下图中左边是理想的显示效果,右边则是实际的显示效果,可以看到明显的锯齿。
image.png经过我一番搜索尝试了以下配置,均无任何帮助:
ctx.setShouldAntialias(true)
ctx.setAllowsAntialiasing(true)
ctx.interpolationQuality = .high
layer.allowsEdgeAntialiasing = true
layer.minificationFilter = .trilinear
我回忆起之前用 CGImageContext 缩放图片的时候也没有这个问题啊,难道是因为 UIView 自带的这个 CGContext 无法很好的缩放图片?
于是我想到一个方案:先用一个 CGImageContext 把图片画上去,再弄出一个 CGImage 来,再把这个 CGImage 放到 UIView 的 CGContext 上是否可以呢?
override func draw(_ rect: CGRect) {
guard let ctx = UIGraphicsGetCurrentContext() else { return }
ctx.addRect(bounds)
ctx.setFillColor(UIColor.black.cgColor)
ctx.fillPath()
if var im = image {
// 计算出在当前view的bounds内,保持图片比例最大的size
let size = Math.getMaxSizeWithAspect(size: CGSize(width: bounds.width, height: bounds.height), radioWidthToHeight: im.size.width / im.size.height)
// 再换算成pixel size
let pixelSize = CGSize(width: size.width * layer.contentsScale, height: size.height * layer.contentsScale)
// 创建一个和 pixel size 一样大的 ImageContext
UIGraphicsBeginImageContextWithOptions(pixelSize, true, 1)
guard let imgCtx = UIGraphicsGetCurrentContext() else { return }
// 把 UIImage 画到这个 ImageContext 上
im.draw(in: CGRect(x: 0, y: 0, width: pixelSize.width, height: pixelSize.height))
// 再把 cgImg 搞出来
guard let cgImg = imgCtx.makeImage() else { return }
// 图片直接绘制的话,会上下翻转,因此先翻转一下
ctx.scaleBy(x: 1, y: -1)
ctx.translateBy(x: 0, y: -bounds.height)
// 再把cgImg 画到 UIView 的 Context 上,大功告成
ctx.draw(cgImg, in: CGRect(x: (bounds.width - size.width) / 2, y: (bounds.height - size.height) / 2, width: size.width, height: size.height))
}
}
问题就此得到解决。
其实我的本身需求是能快速的更新 image,因为是在做一块类似后期调照片的软件,有很多滑块,拖动后通过 CIFilter 修改照片,所以需要一直更新图像,如果有更好的方法,不妨告诉我一下:D
如果以上内容对你有所帮助,请在这些平台上关注我吧,谢谢:P
网友评论