UIView CGGradient 被裁剪到绘制的“框架”

发布于 2024-09-25 20:54:09 字数 2680 浏览 2 评论 0原文

我正在尝试对 UILabels(或 UIView,如果需要的话将 UILabel 放在顶部)背景进行更复杂的绘制。由于我希望它在用户更改 iPhone 方向时自动调整大小,因此我尝试在子类 drawRect 函数中实现它。我希望能够在代码中调整这一切,如果可能的话,省略对图案图像的需要。

我从以前关于该主题的一些帖子中得到了一些提示:

渐变iPhone 上的 UIView 和 UILabels使 UIView 的背景成为没有子类的渐变

不幸的是他们都没有达到目标,因为我想将渐变与自定义绘图结合起来。我希望 CGGradient 被我正在绘制的线框剪裁(在圆角处可见),但我无法实现这一点。

另一种方法是使用 CAGradientLayer,它似乎工作得很好,但这需要在旋转时对框架进行一些调整,并且无论我如何尝试,渐变层似乎都绘制在文本之上。

我的问题是双重的

  • 如何修改下面的代码以使渐变剪辑到绘制的“框架”
  • 如何使 CAGradientLayer 在 UILabel 的文本后面绘制(或者我是否必须使用 CAGradientLayer 将 UIView 放在 UILabel 后面作为背景)

这是我的drawrect函数:

- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [[UIColor clearColor] CGColor]);
CGContextSetStrokeColorWithColor(c, [strokeColor CGColor]);
CGContextSetLineWidth(c, 1);

CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny + 1;

maxx = maxx - 1;
maxy = maxy - 1;

CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.6, 0.6, 0.6, 1.0,  // Start color
0.3, 0.3, 0.3, 1.0 }; // End color

rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGRect currentBounds = [self bounds];
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds),            CGRectGetMidY(currentBounds));
CGPoint lowCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));

CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);

CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace); 

CGContextMoveToPoint(c, minx, midy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, miny, maxx, midy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, maxy, midx, maxy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, minx, maxy, minx, midy, ROUND_SIZE_INFO);

// Close the path
CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);                
//        return;  

[super drawRect: rect]; 

I'm trying to make a more sophisticated drawing of a UILabels (or a UIView, putting the UILabel on top, should that be required) background. Since I want this to resize automatically when the user changes iPhone orientation, I am trying to implement this in a subclasses drawRect function. I would love to be able to tune this all in code, omitting the need for pattern images, if it's possible.

I got some hints from some former posts on the subject:

Gradients on UIView and UILabels On iPhone
and
Make Background of UIView a Gradient Without Sub Classing

Unfortunately they both miss the target, since I wanted to combine gradient with custom drawing. I want the CGGradient to be clipped by the line frame I am drawing (visible at the rounded corners) but I can't accomplish this.

The alternative would be to use the CAGradientLayer, which seem to work quite good, but that would require some resising of the frame at rotation, and the gradient layer seem to draw on top of the text, no matter how I try.

My question therefor is twofold

  • How do I modify the code below to make the gradient clip to the drawn "frame"
  • How do I make CAGradientLayer draw behind the text of the UILabel (or do I have to put a UIView behind the UILabel with the CAGradientLayer as background)

Here is my drawrect function:

- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [[UIColor clearColor] CGColor]);
CGContextSetStrokeColorWithColor(c, [strokeColor CGColor]);
CGContextSetLineWidth(c, 1);

CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny + 1;

maxx = maxx - 1;
maxy = maxy - 1;

CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.6, 0.6, 0.6, 1.0,  // Start color
0.3, 0.3, 0.3, 1.0 }; // End color

rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGRect currentBounds = [self bounds];
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds),            CGRectGetMidY(currentBounds));
CGPoint lowCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));

CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);

CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace); 

CGContextMoveToPoint(c, minx, midy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, miny, maxx, midy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, maxy, midx, maxy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, minx, maxy, minx, midy, ROUND_SIZE_INFO);

// Close the path
CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);                
//        return;  

[super drawRect: rect]; 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

樱花落人离去 2024-10-02 20:54:09

您正在寻找的是 CGContextClip()

按照代码中的方式创建路径和渐变,然后

CGContextClip(c);
CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);
CGGradientRelease(glossGradient);

(删除对 CGContextDrawLinearGradient 的旧调用)

还请记住在进行任何剪辑之前和之后保存并恢复您的上下文

如果您的剪辑是反向的你想要什么,尝试 CGContextEOClip() (或以相反的顺序绘制你的路径)

What you are looking for is CGContextClip()

Create your path and gradient as in your code, and then

CGContextClip(c);
CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);
CGGradientRelease(glossGradient);

(Remove your old call to CGContextDrawLinearGradient)

Also remember to save and restore your context before and after you do any clipping

If your clipping is inverted from what you want, try CGContextEOClip() (or draw your path in reverse order)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文