控件渐变色的实现(二)—— Core Graphics实现
版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.08.07 |
前言
很多时候视图的颜色并不是单一的,需要渐变或者更炫的色彩,这里我就说一下控件渐变色的实现方法。希望能帮助大家。感兴趣的可以看我上一篇文章。
1. 控件渐变色的实现(一)—— CAGradientLayer实现
功能要求
利用Core Graphics
控件渐变色的实现。
功能实现
Core Graphics
中有两个方法用于绘制渐变颜色:
-
CGContextDrawLinearGradient
可以用于生成线性渐变。 -
CGContextDrawRadialGradient
用于生成圆半径方向颜色渐变。
函数可以自定义path
,无论是什么形状都可以,原理都是用来做Clip
,所以需要在CGContextClip
函数前调用CGContextAddPath
函数把CGPathRef
加入到Context
中。
另外一个需要注意的地方是渐变的方向,方向是由两个点控制的,点的单位就是坐标。因此需要正确从CGPathRef
中找到正确的点,方法当然有很多种看具体实现,下面方法中,我就是简单得通过调用CGPathGetBoundingBox
函数,返回CGPathRef
的矩形区域,然后根据这个矩形取两个点。
1. 线性渐变
还是直接看代码。
#import "JJGradientGraphicVC.h"
#import "Masonry.h"
@interface JJGradientGraphicVC ()
@end
@implementation JJGradientGraphicVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"线性渐变色";
self.view.backgroundColor = [UIColor whiteColor];
//创建CGContextRef
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef contextRef = UIGraphicsGetCurrentContext();
//创建CGMutablePathRef
CGMutablePathRef pathRef = CGPathCreateMutable();
//绘制path
CGRect rect = CGRectMake(50.0, 100.0, 300.0, 250.0);
CGPathMoveToPoint(pathRef, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGPathAddLineToPoint(pathRef, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGPathAddLineToPoint(pathRef, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGPathCloseSubpath(pathRef);
//绘制渐变色
[self drawLinearGradientWithContext:contextRef path:pathRef beginColor:[UIColor redColor].CGColor endColor:[UIColor greenColor].CGColor];
//释放CGMutablePathRef
CGPathRelease(pathRef);
//从上下文中获取图像并显示
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[self.view addSubview:imageView];
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.width.equalTo(@300);
make.height.equalTo(@250);
}];
}
#pragma mark - Object Private Function
- (void)drawLinearGradientWithContext:(CGContextRef)context
path:(CGPathRef)path
beginColor:(CGColorRef)beginColor
endColor:(CGColorRef)endColor;
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = {0.0, 1.0};
NSArray *colorArr = @[(__bridge id)beginColor, (__bridge id)endColor];
CGGradientRef gradientRef = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colorArr, locations);
CGRect pathRect = CGPathGetBoundingBox(path);
//具体方向可根据需求修改
CGPoint startPoint = CGPointMake(CGRectGetMinX(pathRect), CGRectGetMidY(pathRect));
CGPoint endPoint = CGPointMake(CGRectGetMaxX(pathRect), CGRectGetMidY(pathRect));
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextClip(context);
CGContextDrawLinearGradient(context, gradientRef, startPoint, endPoint, 0);
CGContextRestoreGState(context);
CGGradientRelease(gradientRef);
CGColorSpaceRelease(colorSpace);
}
@end
效果图验证会在后面给出。
这里重要的是函数CGContextDrawLinearGradient
。
/** Gradient and shading functions. **/
/* Fill the current clipping region of `context' with a linear gradient from
`startPoint' to `endPoint'. The location 0 of `gradient' corresponds to
`startPoint'; the location 1 of `gradient' corresponds to `endPoint';
colors are linearly interpolated between these two points based on the
values of the gradient's locations. The option flags control whether the
gradient is drawn before the start point or after the end point. */
CG_EXTERN void CGContextDrawLinearGradient(CGContextRef cg_nullable c,
CGGradientRef cg_nullable gradient, CGPoint startPoint, CGPoint endPoint,
CGGradientDrawingOptions options)
CG_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
这个方法的作用是:使用线性渐变填充当前的“上下文”剪切区域startPoint
到endPoint
。 “渐变”的位置0
对应于 的startPoint
;gradient
的位置1
对应于endPoint
, 颜色在这两点之间基于线性插值渐变位置的值。 选项标志控制是否梯度在起始点或终点之后绘制。
2. 圆半径外向渐变
这个可以认为是非线性渐变中的一种。
#import "JJGradientNonliearVC.h"
#import "Masonry.h"
@interface JJGradientNonliearVC ()
@end
@implementation JJGradientNonliearVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"非线性渐变色";
self.view.backgroundColor = [UIColor lightGrayColor];
//创建CGContextRef
UIGraphicsBeginImageContext(self.view.bounds.size);
CGContextRef contextRef = UIGraphicsGetCurrentContext();
//创建CGMutablePathRef
CGMutablePathRef pathRef = CGPathCreateMutable();
//绘制path
CGRect rect = CGRectMake(50.0, 100.0, 300.0, 250.0);
CGPathMoveToPoint(pathRef, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect));
CGPathAddLineToPoint(pathRef, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect));
CGPathAddLineToPoint(pathRef, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect));
CGPathAddLineToPoint(pathRef, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGPathCloseSubpath(pathRef);
//绘制渐变色
[self drawRadiusGradientWithContext:contextRef path:pathRef beginColor:[UIColor redColor].CGColor endColor:[UIColor greenColor].CGColor];
//释放CGMutablePathRef
CGPathRelease(pathRef);
//从上下文中获取图像并显示
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[self.view addSubview:imageView];
[imageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.width.equalTo(@300);
make.height.equalTo(@250);
}];
}
#pragma mark - Object Private Function
- (void)drawRadiusGradientWithContext:(CGContextRef)context
path:(CGPathRef)path
beginColor:(CGColorRef)beginColor
endColor:(CGColorRef)endColor;
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = {0.0, 1.0};
NSArray *colorArr = @[(__bridge id)beginColor, (__bridge id)endColor];
CGGradientRef gradientRef = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef) colorArr, locations);
CGRect pathRect = CGPathGetBoundingBox(path);
//具体方向可根据需求修改
CGPoint centerPoint = CGPointMake(CGRectGetMidX(pathRect), CGRectGetMidY(pathRect));
CGFloat radius = MAX(pathRect.size.width * 0.5, pathRect.size.height * 0.5) * sqrt(2);
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGContextClip(context);
CGContextDrawRadialGradient(context, gradientRef, centerPoint, 0, centerPoint, radius, 0);
CGContextRestoreGState(context);
CGGradientRelease(gradientRef);
CGColorSpaceRelease(colorSpace);
}
@end
后面会给出这个效果图。
这里重要的函数是CGContextDrawRadialGradient(context, gradientRef, centerPoint, 0, centerPoint, radius, 0);
/* Fill the current clipping region of `context' with a radial gradient
between two circles defined by the center point and radius of each
circle. The location 0 of `gradient' corresponds to a circle centered at
`startCenter' with radius `startRadius'; the location 1 of `gradient'
corresponds to a circle centered at `endCenter' with radius `endRadius';
colors are linearly interpolated between these two circles based on the
values of the gradient's locations. The option flags control whether the
gradient is drawn before the start circle or after the end circle. */
CG_EXTERN void CGContextDrawRadialGradient(CGContextRef cg_nullable c,
CGGradientRef cg_nullable gradient, CGPoint startCenter, CGFloat startRadius,
CGPoint endCenter, CGFloat endRadius, CGGradientDrawingOptions options)
CG_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
它的作用是:用径向渐变填充当前的“上下文”裁剪区域 在由中心点和每个半径定义的两个圆之间圈。 “渐变”的位置0
对应于以圆为中心的圆 startCenter
,半径为startRadius
; “渐变”的位置1
对应于以endCenter
为中心的圆圈,半径为endRadius
; 基于此,这两个圆之间的颜色被线性内插 渐变位置的值。 选项标志控制是否梯度在起始圆之前或结束圆之后绘制。
功能效果
先看一下线性渐变的效果。
线性渐变下面看一下圆半径外向渐变色效果。
圆半径外向渐变可见,均可实现效果。
后记
秋意浓未完,待续~~~