3

更新:正确绘制矩形方法如下所示

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    if(layer == nil)
    {
        float scale = [UIScreen mainScreen].scale;
        CGRect bounds = CGRectMake(0, 0, rect.size.width *scale, rect.size.height *scale);
        layer = CGLayerCreateWithContext(context, bounds.size, NULL);
        layerContext = CGLayerGetContext(layer);
        CGContextScaleCTM(layerContext, scale, scale);
        viewRect = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
    }

    UIBezierPath *bezierPath = path.bezierPath;
    CGContextAddPath(layerContext, bezierPath.CGPath);
    CGContextSetLineWidth(layerContext, path.width);
    CGContextSetStrokeColorWithColor(layerContext, path.color.CGColor);
    CGContextSetLineCap(layerContext, kCGLineCapRound);
    CGContextStrokePath(layerContext);

    CGContextDrawLayerInRect(context, viewRect, layer);
    self.empty = NO;
}

更新:我按照建议完成了,添加了数组路径并绘制到 CGLayer,如下所示。但是,当绘制大量路径时,性能确实会变慢。我犯过什么错误吗?

    - (void)pan:(UIPanGestureRecognizer *)pan
{
    CGPoint velocity = [pan velocityInView:self];

    previousPoint2 = previousPoint1;
    previousPoint1 = currentPoint;
    currentPoint = [pan locationInView:self];

    float velocityMagnitude = sqrtf(velocity.x * velocity.x + velocity.y * velocity.y);

    float clampedVelocityMagnitude = clamp(VELOCITY_CLAMP_MIN, VELOCITY_CLAMP_MAX, velocityMagnitude);
    float normalizedVelocity = (clampedVelocityMagnitude - VELOCITY_CLAMP_MIN) / (VELOCITY_CLAMP_MAX - VELOCITY_CLAMP_MIN);

    float lowPassFilterAlpha = STROKE_WIDTH_SMOOTHING;
    float newThickness = (STROKE_WIDTH_MAX - STROKE_WIDTH_MIN) * normalizedVelocity + STROKE_WIDTH_MIN;
    self.lineWidth = self.lineWidth * lowPassFilterAlpha + newThickness * (1 - lowPassFilterAlpha);

    CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
    CGPoint mid2 = midPoint(currentPoint, previousPoint1);
    CGMutablePathRef subpath = CGPathCreateMutable();
    CGPathMoveToPoint(subpath, NULL, mid1.x, mid1.y);
    CGPathAddQuadCurveToPoint(subpath, NULL, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
    CGRect bounds = CGPathGetBoundingBox(subpath);

    Path *path = [[Path alloc] init];
    path.width = self.lineWidth;
    path.color = [UIColor redColor];
    path.bezierPath = [UIBezierPath bezierPathWithCGPath:subpath];
    [pathArray addObject:path];
    CGPathRelease(subpath);

    CGRect drawBox = bounds;
    drawBox.origin.x -= self.lineWidth * 2.0;
    drawBox.origin.y -= self.lineWidth * 2.0;
    drawBox.size.width += self.lineWidth * 4.0;
    drawBox.size.height += self.lineWidth * 4.0;

    [self setNeedsDisplayInRect:drawBox];

    if (pan.state == UIGestureRecognizerStateEnded | pan.state == UIGestureRecognizerStateCancelled)
    {
        self.lineWidth = STROKE_WIDTH_MIN;
    }
}

- (void)drawRect:(CGRect)rect {
    [self.backgroundColor set];
    UIRectFill(rect);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if(layer == nil)
    {
        float scale = [UIScreen mainScreen].scale;
        CGRect bounds = CGRectMake(0, 0, rect.size.width * scale, rect.size.height * scale);
        layer = CGLayerCreateWithContext(context, bounds.size, NULL);
        layerContext = CGLayerGetContext(layer);
    }

    for(int i = 0; i < [pathArray count]; i++)
    {
        Path *path = [pathArray objectAtIndex:i];
        UIBezierPath *bezierPath = path.bezierPath;
        CGContextAddPath(layerContext, bezierPath.CGPath);
        CGContextSetLineWidth(layerContext, path.width);
        CGContextSetStrokeColorWithColor(layerContext, path.color.CGColor);
        CGContextSetLineCap(layerContext, kCGLineCapRound);
        CGContextStrokePath(layerContext);
    }

    CGContextDrawLayerAtPoint(context, CGPointZero, layer);

    self.empty = NO;
}

我正在使用下面的代码根据用户平移手势的速度绘制宽度可变的线条。它工作正常,但是当我靠近或越过之前绘制的线时,它的线宽会改变以匹配当前手势和线的速度。请问如何确保绘制的线条保持最初绘制的粗细?

- (void)pan:(UIPanGestureRecognizer *)pan
{
    CGPoint velocity = [pan velocityInView:self];

    previousPoint2 = previousPoint1;
    previousPoint1 = currentPoint;
    currentPoint = [pan locationInView:self];

    float velocityMagnitude = sqrtf(velocity.x * velocity.x + velocity.y * velocity.y);

    float clampedVelocityMagnitude = clamp(VELOCITY_CLAMP_MIN, VELOCITY_CLAMP_MAX, velocityMagnitude);
    float normalizedVelocity = (clampedVelocityMagnitude - VELOCITY_CLAMP_MIN) / (VELOCITY_CLAMP_MAX - VELOCITY_CLAMP_MIN);

    float lowPassFilterAlpha = STROKE_WIDTH_SMOOTHING;
    float newThickness = (STROKE_WIDTH_MAX - STROKE_WIDTH_MIN) * normalizedVelocity + STROKE_WIDTH_MIN;
    self.lineWidth = self.lineWidth * lowPassFilterAlpha + newThickness * (1 - lowPassFilterAlpha);

    CGPoint mid1 = midPoint(previousPoint1, previousPoint2);
    CGPoint mid2 = midPoint(currentPoint, previousPoint1);
    CGMutablePathRef subpath = CGPathCreateMutable();
    CGPathMoveToPoint(subpath, NULL, mid1.x, mid1.y);
    CGPathAddQuadCurveToPoint(subpath, NULL, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
    CGRect bounds = CGPathGetBoundingBox(subpath);

    CGPathAddPath(path, NULL, subpath);
    CGPathRelease(subpath);

    CGRect drawBox = bounds;
    drawBox.origin.x -= self.lineWidth * 2.0;
    drawBox.origin.y -= self.lineWidth * 2.0;
    drawBox.size.width += self.lineWidth * 4.0;
    drawBox.size.height += self.lineWidth * 4.0;

    if (pan.state == UIGestureRecognizerStateEnded | pan.state == UIGestureRecognizerStateCancelled)
    {
        self.lineWidth = STROKE_WIDTH_MIN;
    }
    else
    {
         [self setNeedsDisplayInRect:drawBox];
    }
}

- (void)drawRect:(CGRect)rect {
    [self.backgroundColor set];
    UIRectFill(rect);

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextAddPath(context, path);
    CGContextSetLineCap(context, kCGLineCapRound);

    CGContextSetLineWidth(context, self.lineWidth);
    CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);

    CGContextStrokePath(context);

    self.empty = NO;
}
4

1 回答 1

0

每次线宽发生变化时,您都需要开始一条新路径。您需要将所有这些路径存储到一个数组(或类似的)中,并在drawRect:调用时绘制它们中的每一个。这将在绘图时保持线宽。

当前发生的情况是您总是在绘制一条路径,因此您总是在重置整个路径的线宽。只是您是仅刷新的视图,drawBox因此这是您实际看到的唯一更新的部分。

添加更多行时性能会很差,因此您可能希望开始考虑使用 aCGLayer来缓存先前绘制的路径并将图层渲染到上下文中,drawRect:而不是迭代路径。

于 2013-10-28T18:40:25.007 回答