iOS一个方法搞定view渐变色

2018 年 8 月 13 日 CocoaChina

本公众号内容均为本号转发,已尽可能注明出处。因未能核实来源或转发内容图片有权利瑕疵的,请及时联系本号,本号会第一时间进行修改或删除。 QQ : 3442093904 


Demo

ZCategory


使用效果

//包含头文件UIView+Gradient.h

[self.label setGradientBackgroundWithColors:@[[UIColor redColor],[UIColor orangeColor]] locations:nil startPoint:CGPointMake(00) endPoint:CGPointMake(10)];

[self.btn setGradientBackgroundWithColors:@[[UIColor redColor],[UIColor orangeColor]] locations:nil startPoint:CGPointMake(00) endPoint:CGPointMake(10)];

[self.tempView setGradientBackgroundWithColors:@[[UIColor redColor],[UIColor orangeColor]] locations:nil startPoint:CGPointMake(00) endPoint:CGPointMake(10)];



常规方案


说起颜色渐变一般来说有两种实现方式,一是使用CAGradientLayer而是使用Core Graphics的相关方法,具体可参考ios实现颜色渐变的几种方法


问题


CAGradientLayer可以说是实现起来比较方便的一个方案了,但是对于Autolayout来说,我们需要更新CAGradientLayer的frame,这就得增加不少代码,而且代码会散布在其他方法中,这就不是很友好了。


优化方案


原理


我们知道UIView显示的内容实际是绘制在CALayer上的,默认情况下创建一个UIView时会创建一个CALayer作为UIView的root layer,那么如果我们直接把这个root layer替换成CAGradientLayer就能直接实现渐变效果,而且跟随UIView的frame变化。


那么如何替换呢?UIView有个+layerClass类方法,官方描述:


Returns the class used to create the layer for instances of this class.


This method returns the CALayer class object by default. Subclasses can override this method and return a different layer class as needed. For example, if your view uses tiling to display a large scrollable area, you might want to override this method and return the CATiledLayer class.


This method is called only once early in the creation of the view in order to create the corresponding layer object.


大概意思就是系统默认会返回CALayer类,但是如果你重写了这个类方法,那么就会返你return的类,从而创建你需要的layer。


在实际实现这个分类的时候发现+layerClass有点类似+load方法,即只要文件在项目中,就会调用该方法,不需要显式包含头文件。


实现


我们创建一个UIView的分类UIView+Gradient,利用runtime添加CAGradientLayer的一些属性以及设置背景色的方法,如下:

//UIView+Gradient.h
@property(nullablecopyNSArray *colors;
@property(nullablecopyNSArray<NSNumber *> *locations;
@property CGPoint startPoint;
@property CGPoint endPoint;

+ (UIView *_Nullable)gradientViewWithColors:(NSArray<UIColor *> *_Nullable)colors locations:(NSArray<NSNumber *> *_Nullable)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint;

- (void)setGradientBackgroundWithColors:(NSArray<UIColor *> *_Nullable)colors locations:(NSArray<NSNumber *> *_Nullable)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint;


然后在.m文件中对重写类方法+layerClass以及实现相关设置:

//UIView+Gradient.m

+ (Class)layerClass {
    return [CAGradientLayer class];
}

+ (UIView *)gradientViewWithColors:(NSArray<UIColor *> *)colors locations:(NSArray<NSNumber *> *)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {
    UIView *view = [[self alloc] init];
    [view setGradientBackgroundWithColors:colors locations:locations startPoint:startPoint endPoint:endPoint];
    return view;
}

- (void)setGradientBackgroundWithColors:(NSArray<UIColor *> *)colors locations:(NSArray<NSNumber *> *)locations startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint {
    NSMutableArray *colorsM = [NSMutableArray array];
    for (UIColor *color in colors) {
        [colorsM addObject:(__bridge id)color.CGColor];
    }
    self.colors = [colorsM copy];
    self.locations = locations;
    self.startPoint = startPoint;
    self.endPoint = endPoint;
}


然后就能像最开始提到的那样轻松的一句话设置渐变背景色了。


注意事项


大部分View在设置colors属性后原有的backgroundColor属性会失效,即不管backgroundColor设置的是什么颜色,都会显示渐变色,要显示正常的backgroundColor只需要将colors设置成nil。

// colors优先级高于backgroundColor的View
    UIView
    UIButton 
    UIImageView
    UITextView
    UITextField
    UISlider
    UIStepper
    UISwitch
    UISegmentedControl


在实测中发现UILabel在设置colors后还是会显示backgroundColor,要显示渐变色需要将backgroundColor设置为clearColor。


虽然在UIView的分类中重写了+layerClass,但是有可能存在一些View 已经重写了+layerClass,那么就有可能该View的layer并不是CAGradientLayer,而是其他类型的layer,如UILabel的layer其实是_UILabelLayer,我们在设置layer属性时不能确保这个layer就是CAGradientLayer,需要加个判断:

   if ([self.layer isKindOfClass:[CAGradientLayer class]]) {
        // do something
    }


否则可能会出现崩溃。


对于UILabel这种貌似已经重写过+layerClass方法的view,我目前是直接在其分类中再次重写+layerClass方法

//  UIView+Gradient.m
    @implementation UILabel (Gradient)
    + (Class)layerClass {
     return [CAGradientLayer class];
    }
    @end


将_UILabelLayer替换为CAGradientLayer除了colors和backgroundColor的优先级不同其他还有什么影响暂时不清楚。


作者:水暮竹妖

链接:https://www.jianshu.com/p/e7c9e94e165b


相关推荐:


登录查看更多
0

相关内容

Python计算导论,560页pdf,Introduction to Computing Using Python
专知会员服务
72+阅读 · 2020年5月5日
【芝加哥大学】可变形的风格转移,Deformable Style Transfer
专知会员服务
30+阅读 · 2020年3月26日
MIT公开课-Vivienne Sze教授《深度学习硬件加速器》,86页ppt
【新书】Java企业微服务,Enterprise Java Microservices,272页pdf
强化学习最新教程,17页pdf
专知会员服务
174+阅读 · 2019年10月11日
已删除
AI掘金志
7+阅读 · 2019年7月8日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
Linux挖矿病毒的清除与分析
FreeBuf
14+阅读 · 2019年4月15日
从webview到flutter:详解iOS中的Web开发
前端之巅
5+阅读 · 2019年3月24日
iOS自定义带动画效果的模态框
CocoaChina
7+阅读 · 2019年3月3日
A Technical Overview of AI & ML in 2018 & Trends for 2019
待字闺中
16+阅读 · 2018年12月24日
tensorflow LSTM + CTC实现端到端OCR
机器学习研究会
26+阅读 · 2017年11月16日
Arxiv
24+阅读 · 2020年3月11日
Monocular Plan View Networks for Autonomous Driving
Arxiv
6+阅读 · 2019年5月16日
Arxiv
5+阅读 · 2018年4月30日
Arxiv
3+阅读 · 2018年3月22日
Arxiv
6+阅读 · 2018年2月8日
Arxiv
3+阅读 · 2012年11月20日
VIP会员
相关资讯
已删除
AI掘金志
7+阅读 · 2019年7月8日
7 款实用到哭的App,只说一遍
高效率工具搜罗
84+阅读 · 2019年4月30日
Linux挖矿病毒的清除与分析
FreeBuf
14+阅读 · 2019年4月15日
从webview到flutter:详解iOS中的Web开发
前端之巅
5+阅读 · 2019年3月24日
iOS自定义带动画效果的模态框
CocoaChina
7+阅读 · 2019年3月3日
A Technical Overview of AI & ML in 2018 & Trends for 2019
待字闺中
16+阅读 · 2018年12月24日
tensorflow LSTM + CTC实现端到端OCR
机器学习研究会
26+阅读 · 2017年11月16日
相关论文
Arxiv
24+阅读 · 2020年3月11日
Monocular Plan View Networks for Autonomous Driving
Arxiv
6+阅读 · 2019年5月16日
Arxiv
5+阅读 · 2018年4月30日
Arxiv
3+阅读 · 2018年3月22日
Arxiv
6+阅读 · 2018年2月8日
Arxiv
3+阅读 · 2012年11月20日
Top
微信扫码咨询专知VIP会员