【问题标题】:CGGradient: Drawing a linear gradient on an angleCGGradient:在角度上绘制线性渐变
【发布时间】:2026-02-11 08:35:01
【问题描述】:

我正在尝试在某个角度上绘制线性 CGGradient。因为“CGContextDrawLinearGradientWithAngle()”不存在,所以我尝试使用 CGContextDrawLinearGradient(CGContextRef, CGGradientRef, CGPoint startPoint, CGPoint endPoint, CGGradientDrawingOptions)。

考虑到这一点,我需要将角度(度)转换为起点和终点。我想模仿 NSGradient 的 drawInBezierPath:angle。 (遗憾的是,作为 AppKit 的一部分,iOS 开发人员无法使用 NSGradient。)幸运的是,文档告诉我们如何get the starting gradient

- (CGPoint)startingPointForAngle:(CGFloat)angle rect:(CGRect)rect { 
    CGPoint point = CGPointZero;
    if (angle < 90.0f)
        point = CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect));
    else if (angle < 180.0f)
        point = CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect));
    else if (angle < 270.0f)
        point = CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect));
    else
        point = CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect));

    return point;
}

不幸的是,文档没有告诉我们如何获得终点。 (使用矩形的高度或宽度作为距离仅适用于某些角度。)Several sites out there 告诉我们如何找到终点。不幸的是,在我计算终点之前需要知道距离。然而,需要计算终点以获得距离。显然还有更多,因为 NSGradient 似乎已经弄清楚了。

- (CGPoint)endingPointForAngle:(CGFloat)angle rect:(CGRect)rect startingPoint:(CGPoint)startingPoint {
    //http://www.zahniser.net/~russell/computer/index.php?title=Angle%20and%20Coordinates
    //(x + distance * cos(a), y + distance * sin(a))
    CGFloat angleInRadians = (CGFloat)M_PI/180.0f * angle;
    CGFloat distance = ????????;
    CGPoint point = CGPointMake(startingPoint.x + distance * cosf(angleInRadians), startingPoint.y + distance * sinf(angleInRadians));
    return point;
}

CGPoint startingGradientPoint = [self startingPointForAngle:self.fillGradientAngle rect:rect];
CGPoint endingGradientPoint = [self endingPointForAngle:self.fillGradientAngle rect:rect startingPoint:startingGradientPoint];
CGContextDrawLinearGradient(graphicsContext, self.fillGradient, startingGradientPoint, endingGradientPoint, 0);

任何想法。

【问题讨论】:

  • 你可以在你的边界矩形周围画一个假想的圆(半径==矩形diagonal的一半(!))并计算angleangle + CGFloat.pi的圆上的两个点。

标签: iphone objective-c ios core-graphics


【解决方案1】:

我正在处理同样的问题,但方式略有不同,我使用中心点和角度,并左右扩展边以找到边缘上的点,我的问题是会有空白如果天使没有指向任何轴,并且绘图选项,函数提供“kCGGradientDrawsBeforeStartLocation 或 kCGGradientDrawsAfterEndLocation”,因此看起来一侧将为空。

但事实证明我可以将这两个选项与'|'结合起来,所以问题解决了,这是我的代码:

CGGradientRef grRef = CGGradientCreateWithColors(colorSpace,  (__bridge CFArrayRef)gradient.colorArray, NULL);
CGFloat degree = angle * M_PI / 180;
CGPoint center = CGPointMake(width/2, height/2);
CGPoint startPoint = CGPointMake(center.x - cos (degree) * width/2, center.y - sin(degree) * height/2);
CGPoint endPoint = CGPointMake(center.x + cos (degree) * width/2, center.y + sin(degree) * height/2);

NSLog(@"start point:%@ \n, end point: %@",NSStringFromCGPoint(startPoint),NSStringFromCGPoint(endPoint));

CGContextDrawLinearGradient(gradientContext, grRef, startPoint, endPoint, kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation);

【讨论】:

    【解决方案2】:

    我不是 100% 确定这个渐变是如何工作的,但从你写的内容来看,我假设你基本上只想要从起点到到达矩形边的直线长度。

    如果是这种情况,您只需要做一些三角函数。让我们称距离 x 和角度 a。

    0 到 45 度之间:width = xcos(a) 所以 x = width/cos(a)

    在 45 到 90 度之间:height = xsin(a) 所以 x = height/sin(a)

    在 90 到 135 度之间,我们已经搬到了一个新的角落。这里 x = height/cos(a-90)。

    在 135 和 180 之间 x = 宽度/sin(a-90)

    在 180 和 225 之间,我们再次移动了角落。这里 x = width/cos(a-180)。

    在 225 和 270 之间 x = 高度/sin(a-180)

    最后一角!在 270 和 315 之间 x = 高度/sin(a-270)

    最后在 315 和 360 之间 x = width/cos(a-270)

    其中一些可能会简化,但最容易考虑的是从左下角开始指向右侧并逆时针旋转的线,这似乎在您的起点计算中发生。

    【讨论】: