【问题标题】:iOS quartz drawing appiOS 石英绘图应用
【发布时间】:2013-11-06 02:16:22
【问题描述】:

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

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

【问题讨论】:

    标签: ios drawing


    【解决方案1】:

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

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

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

    【讨论】:

    • 请看我的问题更新了进一步的进展。这看起来正确吗?谢谢
    • 在drawrect中,想法是绘制图层和“当前”路径,而不是所有路径。该图层应包含预渲染的所有“已保存”路径。
    • 谢谢韦恩,感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多