美文网首页
iOS 提高绘制性能的"脏矩形"

iOS 提高绘制性能的"脏矩形"

作者: 王技术 | 来源:发表于2019-09-15 12:49 被阅读0次

    需求大概是这样 :

    记录手指在屏幕上划过的点, 在点上绘制指定图案.

    思路大概是这样 :

    touchesBegantouchesMoved 记录手指划过的点, 每增加一个点调用 setNeedsDisplaydrawRect 中重绘页面

    代码肥肠的简单 :

    - (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];
            }
        }
    }
    

    修改过后的性能还是很客观的


    本文代码

    相关文章

      网友评论

          本文标题:iOS 提高绘制性能的"脏矩形"

          本文链接:https://www.haomeiwen.com/subject/ajpayctx.html