iOS加载大图

假如你有一张超级大的图片几十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上面,然后实现对应的方法就好了。

demo地址:https://github.com/taozaizai/TYTiedRender

你可能感兴趣的:(iOS加载大图)