我需要制作一個(gè)快速更新 UIImage 的功能,一開(kāi)始使用 UIImageView 來(lái)顯示圖片,所以需要頻繁的調(diào)用 UIImageView.image = newImage 方法來(lái)更新圖片。代碼看起來(lái)像這樣。
func onSomethingChanged() {
myUIImageView.image = newImage
}
這樣更新圖片非常的卡頓,操作和畫(huà)面響應(yīng)有一定的滯后,體驗(yàn)不好,因此考慮自己做一個(gè) UIView 來(lái)繪制圖片,看看是否可以解決。
于是自己自定義了一個(gè) View,繼承 UIView 來(lái)做,在 draw(rect:) 方法里面做文章。
首先當(dāng)然是簡(jiǎn)單粗暴直接 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)
}
}
很好,更新速度很快,是理想的效果,不過(guò)目前畫(huà)面是拉伸的,同時(shí)還有鋸齒。
下圖中左邊是理想的顯示效果,右邊則是實(shí)際的顯示效果,可以看到明顯的鋸齒。

經(jīng)過(guò)我一番搜索嘗試了以下配置,均無(wú)任何幫助:
ctx.setShouldAntialias(true)
ctx.setAllowsAntialiasing(true)
ctx.interpolationQuality = .high
layer.allowsEdgeAntialiasing = true
layer.minificationFilter = .trilinear
我回憶起之前用 CGImageContext 縮放圖片的時(shí)候也沒(méi)有這個(gè)問(wèn)題啊,難道是因?yàn)?UIView 自帶的這個(gè) CGContext 無(wú)法很好的縮放圖片?
于是我想到一個(gè)方案:先用一個(gè) CGImageContext 把圖片畫(huà)上去,再弄出一個(gè) CGImage 來(lái),再把這個(gè) 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 {
// 計(jì)算出在當(dāng)前view的bounds內(nèi),保持圖片比例最大的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)
// 創(chuàng)建一個(gè)和 pixel size 一樣大的 ImageContext
UIGraphicsBeginImageContextWithOptions(pixelSize, true, 1)
guard let imgCtx = UIGraphicsGetCurrentContext() else { return }
// 把 UIImage 畫(huà)到這個(gè) ImageContext 上
im.draw(in: CGRect(x: 0, y: 0, width: pixelSize.width, height: pixelSize.height))
// 再把 cgImg 搞出來(lái)
guard let cgImg = imgCtx.makeImage() else { return }
// 圖片直接繪制的話,會(huì)上下翻轉(zhuǎn),因此先翻轉(zhuǎn)一下
ctx.scaleBy(x: 1, y: -1)
ctx.translateBy(x: 0, y: -bounds.height)
// 再把cgImg 畫(huà)到 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))
}
}
問(wèn)題就此得到解決。
其實(shí)我的本身需求是能快速的更新 image,因?yàn)槭窃谧鲆粔K類似后期調(diào)照片的軟件,有很多滑塊,拖動(dòng)后通過(guò) CIFilter 修改照片,所以需要一直更新圖像,如果有更好的方法,不妨告訴我一下:D
如果以上內(nèi)容對(duì)你有所幫助,請(qǐng)?jiān)?a target="_blank">這些平臺(tái)上關(guān)注我吧,謝謝:P