iOS 提高绘制性能的"脏矩形"
2019-09-15 本文已影响0人
王技术
需求大概是这样 :
记录手指在屏幕上划过的点, 在点上绘制指定图案.
思路大概是这样 :
用
touchesBegan
和touchesMoved
记录手指划过的点, 每增加一个点调用setNeedsDisplay
在drawRect
中重绘页面
代码肥肠的简单 :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint point = [[touches anyObject] locationInView:self];
[self addBrushStrokeAtPoint:point];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint point = [[touches anyObject] locationInView:self];
[self addBrushStrokeAtPoint:point];
}
- (void)addBrushStrokeAtPoint:(CGPoint)point {
[self.strokes addObject:[NSValue valueWithCGPoint:point]];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
for (NSValue *value in self.strokes) {
CGPoint point = [value CGPointValue];
CGRect brushRect = CGRectMake(point.x - BRUSH_SIZE/2, point.y - BRUSH_SIZE/2, BRUSH_SIZE, BRUSH_SIZE);
[[UIImage imageNamed:@"star"] drawInRect:brushRect];
}
}
但是!
这样好像内存和 CPU 都会吃不消 :
这还是在模拟器上, 感觉就快扛不住了, 要是在真机上就更难了
问题就在于手指每移动一点我们就会重绘之前所有的路径
但是大部分场景并没有改变, 做了很多无用功
我们绘制地越多,就会越慢。随着时间的增加每次重绘需要更多的时间,屏幕帧数也会下降
为了减少不必要的绘制, iOS 设备把屏幕分为需要重绘的区域和不需要重绘的区域
那些需要重绘的区域被称为脏区域
但是在实际应用中, 区域的形状复杂, 通常会用包含指定区域的矩形来表示需要绘制区域
这个位置就是脏矩形
当检测到指定视图或图层的某个部分需要被重绘,可以直接调用 -setNeedsDisplayInRect:
来标记它
这样就会在一次视图刷新时调用视图的 -drawRect:
(或图层代理的 -drawLayer:inContext:
方法)重绘时
就只重绘我们标记的区域了
于是我们把代码改成这个样子
#define BRUSH_SIZE 32
- (void)addBrushStrokeAtPoint:(CGPoint)point {
[self.strokes addObject:[NSValue valueWithCGPoint:point]];
[self setNeedsDisplayInRect:[self brushRectForPoint:point]];
}
- (CGRect)brushRectForPoint:(CGPoint)point {
return CGRectMake(point.x - BRUSH_SIZE/2, point.y - BRUSH_SIZE/2, BRUSH_SIZE, BRUSH_SIZE);
}
- (void)drawRect:(CGRect)rect {
for (NSValue *value in self.strokes) {
CGPoint point = [value CGPointValue];
CGRect brushRect = [self brushRectForPoint:point];
if (CGRectIntersectsRect(rect, brushRect)) {
[[UIImage imageNamed:@"star"] drawInRect:brushRect];
}
}
}
修改过后的性能还是很客观的