iPhone上的UIView和UILabels上的渐变[重复]
Posted
技术标签:
【中文标题】iPhone上的UIView和UILabels上的渐变[重复]【英文标题】:Gradients on UIView and UILabels On iPhone [duplicate] 【发布时间】:2010-09-30 03:22:24 【问题描述】:可能重复:Manually drawing a gradient in iPhone apps?
我的应用程序需要在UIView
或UILabel
中显示文本,但背景必须是渐变色,而不是真正的UIColor
。使用图形程序创建所需的外观并不好,因为文本可能会因服务器返回的数据而异。
有人知道解决这个问题的最快方法吗? 非常感谢您的想法。
【问题讨论】:
【参考方案1】:注意:以下结果适用于旧版本的 ios,但在 iOS 13 上测试时不会出现步进。我不知道在哪个版本的 iOS 上移除了步进。
使用CAGradientLayer
时,与CGGradient
相比,渐变不平滑,但有明显的步进。见:
要获得更有吸引力的结果,最好使用CGGradient
。
【讨论】:
您介意发布与 Mirko Froehlich 的 CGGradient 示例等效的代码吗? Brad Larson 上面使用 CGGradient 的代码已经足够好了。我会在其中一个答案上发表评论,但我还没有足够的分数。 重要提示:我最近删除了我的 CGGradient 代码并将其替换为 CAGradientLayer。你知道为什么?我在 30 个单元上绘制它,性能影响很大。 CAGradient 在性能方面要好得多(解释了微小的质量差异)。 如果要添加渐变的视图高度很小,我猜 CAGradientLayer 是您可以承受的折衷方案。如果视图高度很重要,最好使用 CGGradient。因此,您不太可能在滚动视图中放置更高高度的视图。 对于 Mazyod 的评论,如果您发现自己以相同的方式多次生成相同的渐变(或任何其他绘图操作)并且影响性能,请考虑只执行一次,将结果缓存到 UIImage并反复使用。也适用于多层绘图。【参考方案2】:您可以使用 Core Graphics 来绘制渐变,正如 Mike 的回复中所指出的那样。作为更详细的示例,您可以创建一个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
顶部到其垂直中心的白色光泽样式渐变。您可以将UIView
的backgroundColor
设置为任何您喜欢的颜色,这种光泽将绘制在该颜色之上。您还可以使用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 是什么?【参考方案3】: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,为什么不将渐变层存储为实例属性并在不再需要时将其删除?【参考方案4】:这就是我在 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 并使用 highlight 方法:“- (void)setHighlighted:(BOOL)highlight if (highlight != self.highlighted)” 在这里面,做图层切换器。效果很好。 并且,在这里详细写了:banane.com/2012/06/01/iphone-gradient-buttons-with-highlighting 如何从视图中移除这个 CAGradientLayer ? 找到它并将其从按钮的视图层中删除,如果我记得的话。【参考方案5】:我意识到这是一个较旧的线程,但供将来参考:
从 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]
(或等效项)【参考方案6】:
我在一个带有 UIImageView 子视图的视图中实现了这一点。 ImageView 指向的图像是渐变的。然后我在 UIView 中设置了一个背景颜色,我有一个彩色渐变视图。接下来我根据需要使用视图,我绘制的所有内容都将在这个渐变视图下。通过在 ImageView 顶部添加第二个视图,您可以选择绘制是否低于或高于渐变...
【讨论】:
【参考方案7】:您还可以使用一个像素宽的图形图像作为渐变,并设置 view 属性以扩展图形以填充视图(假设您正在考虑简单的线性渐变而不是某种径向图形)。
【讨论】:
使用这种方法,请确保有两种不同的渐变:一种用于常规显示器,一种用于视网膜显示器。 与编码解决方案相比,此解决方案的一个重要好处是颜色渐变通常是一种装饰属性,根本不应该在代码中表达。这就是图形专家的目的。编写代码来表达颜色是逻辑与表示的一个很差的分离。当营销团队决定更改颜色,而图形人员询问如何做到这一点时,他不会喜欢被告知您只需调整 MyLabelView.m 中CAGradientLayer
上的颜色数组......而且他也不应该.对于一个人的商店来说并不重要,但对于团队来说却很重要。
我同意 Nate 的观点,让设计师尽可能轻松地更改资产是一件好事。
@Nate - 您的逻辑代码应该与您的演示代码分开。这并不意味着您唯一可能的解决方案是拥有一个图形文件,而且坦率地说,对于应用程序中的每个位图,您都在为将来的更多工作做好准备。渐变代码总是看起来很棒。只有在 Apple 决定再次提高屏幕分辨率之前,您的位图才会看起来不错。
同样适用于具有动态高度的视图,例如高度取决于它必须容纳多少文本的单元格。以上是关于iPhone上的UIView和UILabels上的渐变[重复]的主要内容,如果未能解决你的问题,请参考以下文章
iPhone UIScrollview:当位于 Scroll View 的子 UIView 上的 480 像素以下时,按钮不响应