ChatGPT解决这个技术问题 Extra ChatGPT

iPhone上的UIView和UILabels上的渐变[重复]

这个问题在这里已经有了答案:9 年前关闭。

可能重复:在 iPhone 应用程序中手动绘制渐变?

我的应用程序需要在 UIViewUILabel 中显示文本,但背景必须是渐变而不是真正的 UIColor。使用图形程序创建所需的外观并不好,因为文本可能会因服务器返回的数据而异。

有谁知道解决这个问题的最快方法?非常感谢您的想法。


M
Mirko Froehlich

我意识到这是一个较旧的线程,但供将来参考:

从 iPhone SDK 3.0 开始,使用新的 CAGradientLayer 可以非常轻松地实现自定义渐变,无需子类或图像:

 UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)] autorelease];
 CAGradientLayer *gradient = [CAGradientLayer layer];
 gradient.frame = view.bounds;
 gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];
 [view.layer insertSublayer:gradient atIndex:0];

看看 CAGradientLayer 文档。您可以选择指定起点和终点(以防您不想要从顶部直接到底部的线性渐变),甚至可以指定映射到每种颜色的特定位置。


以防我的评论在考虑实施上述其他解决方案时引起任何人的注意,请执行此操作。它再简单不过了(但请记住,您需要添加 QuartzCore 框架并在您的类中导入 #import <QuartzCore/QuartzCore.h>)。
有人可能会应用额外的效果,例如cornerRadius。他们必须在此处添加更多代码:view.layer.masksToBounds = YES; 以确保一切顺利。
我的实验表明,具有固定梯度图像的图像显示出比使用 CAGradientLayer 更好的性能。
嗯。使用此解决方案时,我的标签文本消失了。
@HiveHicks 我发现如果我使用 CAGradientLayer 作为 UILabel 我必须将 backgroundColor 设置为 [UIColor clearColor] (或等效)
p
pablasso

正如迈克的回应所指出的,您可以使用 Core Graphics 来绘制渐变。作为更详细的示例,您可以创建一个 UIView 子类以用作 UILabel 的背景。在该 UIView 子类中,覆盖 drawRect: 方法并插入类似于以下内容的代码:

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

    CGGradientRef glossGradient;
    CGColorSpaceRef rgbColorspace;
    size_t num_locations = 2;
    CGFloat locations[2] = { 0.0, 1.0 };
    CGFloat components[8] = { 1.0, 1.0, 1.0, 0.35,  // Start color
         1.0, 1.0, 1.0, 0.06 }; // 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));
    CGContextDrawLinearGradient(currentContext, glossGradient, topCenter, midCenter, 0);

    CGGradientRelease(glossGradient);
    CGColorSpaceRelease(rgbColorspace); 
}

此特定示例创建了一个从 UIView 顶部到其垂直中心的白色光泽样式渐变。您可以将 UIViewbackgroundColor 设置为您喜欢的任何值,此光泽将绘制在该颜色之上。您还可以使用 CGContextDrawRadialGradient 函数绘制径向渐变。

您只需适当调整此 UIView 的大小并将您的 UILabel 添加为它的子视图即可获得所需的效果。

编辑(2009 年 4 月 23 日):根据 St3fan 的建议,我已经用代码中的边界替换了视图的框架。这更正了视图原点不是 (0,0) 的情况。


我试过这段代码,但它不正确。与其将 currentFrame 设置为 self.frame,不如将其设置为 self.bounds。
你是对的,谢谢指出。我已经更正了自己的代码,但忘记了这需要更新。得到你的情况是当视图的原点的 Y 位置不同于 0 时。然后绘制梯度偏离垂直中心。
这可以应用于 UIImage 或 UIImageView 以获得任何带有渐变的图像吗?
您可以将它放在 UIImageView 上以添加渐变。要更改图像的内容,您可能需要首先将图像绘制到上下文中,在该上下文中在其上方绘制渐变,然后将上下文保存为新图像。
您能告诉我在使用以下内容时如何确定颜色:CGFloat components[8] = { 1.0, 1.0, 1.0, 0.35, 1.0, 1.0, 1.0, 0.06 };例如,您怎么知道 1.0 和 0.35 是什么?
T
ThomasW

注意:以下结果适用于旧版本的 iOS,但在 iOS 13 上进行测试时,不会发生步进。我不知道删除了哪个版本的 iOS。

https://i.stack.imgur.com/NlPaw.png

要获得更有吸引力的结果,最好使用 CGGradient


您介意发布与 Mirko Froehlich 的 CGGradient 示例等效的代码吗?
上面使用 CGGradient 的 Brad Larson 的代码已经足够好了。我本来可以对其中一个答案发表评论,但我还没有足够的分数。
重要提示:我最近删除了我的 CGGradient 代码并将其替换为 CAGradientLayer。你知道为什么?我在 30 个单元上绘制它,性能影响很大。 CAGradient 在性能方面要好得多(解释了微小的质量差异)。
如果您要添加渐变的视图高度很小,我猜 CAGradientLayer 是您可以承受的折衷方案。如果视图高度很重要,最好使用 CGGradient。因此,您不太可能在滚动视图中放置更大高度的视图。
对于 Mazyod 的评论,如果您发现自己以相同的方式多次生成相同的渐变(或任何其他绘图操作)并且影响性能,请考虑只执行一次,将结果缓存到 UIImage 并重复使用。也适用于多层绘图。
K
Kendall Helmstetter Gelner

您还可以使用一个像素宽的图形图像作为渐变,并设置视图属性以扩展图形以填充视图(假设您正在考虑简单的线性渐变而不是某种径向图形)。


使用这种方法,请确保有两种不同的渐变:一种用于常规显示器,一种用于视网膜显示器。
与编码解决方案相比,此解决方案的一个重要好处是颜色渐变通常是一种装饰属性,根本不应该在代码中表达。这就是图形专家的目的。编写代码来表达颜色是逻辑与表示的一个很差的分离。当营销团队决定更改颜色时,图形人员询问如何执行此操作,他不会喜欢被告知您只需调整 MyLabelView.m 中 CAGradientLayer 上的颜色数组......而且他也不应该.对于一个人的商店来说并不重要,但对于团队来说却很重要。
我同意 Nate 的观点,让设计师尽可能轻松地更改资产可能会很好。
@Nate - 您的逻辑代码应该与您的演示代码分开。这并不意味着您唯一可能的解决方案是拥有一个图形文件,而且坦率地说,对于您的应用程序中的每个位图,您都在为将来的更多工作做好准备。渐变代码总是看起来很棒。只有在 Apple 决定再次提高屏幕分辨率之前,您的位图才会看起来不错。
同样适用于具有动态高度的视图,例如高度取决于它必须容纳多少文本的单元格。
J
Jeff Lambert

Mirko Froehlich 的回答对我有用,除非我想使用自定义颜色。诀窍是使用色调、饱和度和亮度而不是 RGB 来指定 UI 颜色。

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = myView.bounds;
UIColor *startColour = [UIColor colorWithHue:.580555 saturation:0.31 brightness:0.90 alpha:1.0];
UIColor *endColour = [UIColor colorWithHue:.58333 saturation:0.50 brightness:0.62 alpha:1.0];
gradient.colors = [NSArray arrayWithObjects:(id)[startColour CGColor], (id)[endColour CGColor], nil];
[myView.layer insertSublayer:gradient atIndex:0];

要获得颜色的色调、饱和度和亮度,请使用内置的 xcode 颜色选择器并转到 HSB 选项卡。在此视图中,色调以度数为单位,因此将该值除以 360 即可获得您要在代码中输入的值。


我可以添加这个 CAGradientLayer,但是如何从 myView 中删除它?在绘制 CAGradientLayer 之前,我想拥有之前的视图。有这个吗?
我会遍历 myView.layer.sublayers,直到你得到 CAGradientLayer,然后调用 removeFromSuperlayer。 for (CALayer *currentLayer in [self.view.layer sublayers]) { if([currentLayer isKindOfClass: [CAGradientLayer class]] ) { [currentLayer removeFromSuperlayer]; } }
Wtf,为什么不将渐变层存储为实例属性并在不再需要时将其删除?
A
Anna Billstrom

这就是我在 xCode 的 IB 中将工作集 UIButton 设置为透明/清晰,并且没有背景图像。

UIColor *pinkDarkOp = [UIColor colorWithRed:0.9f green:0.53f blue:0.69f alpha:1.0];
UIColor *pinkLightOp = [UIColor colorWithRed:0.79f green:0.45f blue:0.57f alpha:1.0];

CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = [[shareWordButton layer] bounds];
gradient.cornerRadius = 7;
gradient.colors = [NSArray arrayWithObjects:
                   (id)pinkDarkOp.CGColor,
                   (id)pinkLightOp.CGColor,
                   nil];
gradient.locations = [NSArray arrayWithObjects:
                      [NSNumber numberWithFloat:0.0f],
                      [NSNumber numberWithFloat:0.7],
                      nil];

[[recordButton layer] insertSublayer:gradient atIndex:0];

好的改变——我现在继承 UIButton 并使用高亮方法:“- (void)setHighlighted:(BOOL)highlight { if (highlight != self.highlighted){” 在这里面,做图层切换。效果很好。
如何从视图中删除此 CAGradientLayer ?
如果我记得的话,找到它并将其从按钮的视图层中删除。
m
mahboudz

我在一个带有 UIImageView 子视图的视图中实现了这一点。 ImageView 指向的图像是渐变的。然后我在 UIView 中设置了一个背景颜色,我有一个彩色渐变视图。接下来我根据需要使用视图,我绘制的所有内容都将在这个渐变视图下。通过在 ImageView 顶部添加第二个视图,您可以选择一些选项,无论您的绘图是低于还是高于渐变...