假如你有一张超级大的图片几十m的那种,你会怎么做呢?
直接使用UIImageview吗?那样内存会瞬间爆掉的。苹果提供了一个类来专门干这个事,CATiledLayer。
思想很简单,就是把大图切割成很多个小图,然后在CATiledLayer的drawRect方法里决定哪一部分该加载哪一张小图,因为是实时绘制的,即绘制完一张图片就释放掉一张图片,所以内存方面基本没有增长,当你放大或者缩小时,就会触发CATiledLayer的drawRect方法。
关键点:
首先,你需要有一个自定义的CATiledLayer
图片切割,取得指定行列的小图:
func prepareForSource(atCol col: Int, row: Int) -> UIImage? {
var width = tileSize
var height = tileSize
//最后一列
if col == totalCol-1 {
width = lastColWidth
}
if row == totalRow-1 {
height = lastRowHeight
}
if width == 0 || height == 0 {
return nil
}
let tileImage: CGImage = cgSourceImage!.cropping(to: CGRect(x: CGFloat(
CGFloat(col) * tileSize), y: CGFloat(CGFloat(row) * tileSize), width: width, height: tileSize))!
return UIImage(cgImage: tileImage)
}
drawRect计算哪张图片绘制到那个rect
override func draw(_ rect: CGRect) {
let ctx: CGContext? = UIGraphicsGetCurrentContext()
let bounds: CGRect = rect
//draw tile
let blockSize: CGSize = self.blockSize
let firstCol = Int(bounds.origin.x / blockSize.width)
let lastCol = Int((bounds.origin.x + bounds.size.width) / blockSize.width - 1)
let firstRow = Int(bounds.origin.y / blockSize.height)
let lastRow = Int((bounds.origin.y + bounds.size.height) / blockSize.height - 1)
//防止过度放大
if (firstRow >= lastRow || firstCol >= lastCol) && (firstCol != totalCol - 1 && lastCol != totalCol - 1 && firstRow != totalRow - 1 && lastRow != totalRow - 1) {
return
}
var i = 0
for row in firstRow...lastRow {
UIGraphicsPushContext(ctx!)
for col in firstCol...lastCol {
//load tile image
let tileImage: UIImage? = prepareForSource(atCol: col, row: row)
if tileImage == nil {
continue
}
let drawRect = CGRect(x: CGFloat(col * Int(blockSize.width)), y: CGFloat(row * Int(blockSize.height)), width: CGFloat(blockSize.width), height: CGFloat(blockSize.height))
tileImage?.draw(in: drawRect)
I+=1
}
UIGraphicsPopContext()
}
当然要实现缩放,你得把视图放在一个scrollview上面,然后实现对应的方法就好了。
网友评论