漸變圖層通常與插值貝塞爾曲線混合使用來繪制各種變化曲線魄揉。剛開始也是公司需求剪侮,要繪制這種光滑的曲線,我也找了很多的第三方洛退,帶動畫的瓣俯、不帶動畫的種種杰标,結(jié)果都不滿意,然后就開始自己搞彩匕,其中同事也給了我很多提示腔剂。
貝塞爾曲線可能都會畫,但是于要求還遠遠不夠驼仪,怎么畫出光滑的曲線掸犬,再加上漸變的圖層,這就是關(guān)鍵了绪爸,下面的代碼主要講解處理插值數(shù)據(jù)湾碎,讓貝塞爾曲線更加光滑,通過貝塞爾曲線繪制漸變圖層毡泻。俗話說授人以魚不如授人以漁胜茧,下面就以代碼來講解實現(xiàn)和使用的方法粘优,讓初學者都能自己寫自己想要的曲線圖仇味。
講解全靠代碼注釋
GradeColorView類,.h文件
#import <UIKit/UIKit.h>
@interface GradeColorView : UIView
@property(strong,nonatomic)UIColor * lineColor;/////線的顏色
@property (nonatomic, strong)NSMutableArray *allPoints;///所有點包括插值點
- (instancetype)initWithFrame:(CGRect)frame;
- (void)updateUIWithPointArray:(NSArray *)pointsArray insertNum:(NSInteger)insertNum withLineColor:(UIColor *)color;
@end
.m文件
#import "GradeColorView.h"
#import "DataGetY.h"
///把對應(yīng)的顏色
#define kSetAlColor(rd,ge,be,al) ([UIColor colorWithRed:rd<=1?rd:rd/255.0 green:ge<=1?ge:ge/255.0 blue:be<=1?be:be/255.0 alpha:al])
//獲取顏色R G B
#define kGetColorRed(color) ([[[CIColor alloc]initWithColor:color] red])
#define kGetColorGreen(color) ([[[CIColor alloc]initWithColor:color] green])
#define kGetColorBlue(color) ([[[CIColor alloc]initWithColor:color] blue])
@interface GradeColorView ()
@property (nonatomic, strong)CAGradientLayer *gradientLayer;////漸變色層
@property (nonatomic, strong)NSArray *pointsArray;////曲線的點數(shù)組
@property (nonatomic, assign)NSInteger insertNum;
@end
@implementation GradeColorView
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.allPoints = [[NSMutableArray alloc]init];
}
return self;
}
////傳入數(shù)據(jù) 數(shù)組
- (void)updateUIWithPointArray:(NSArray *)pointsArray insertNum:(NSInteger)insertNum withLineColor:(UIColor *)color
{
self.lineColor = color;///設(shè)置曲線顏色
self.insertNum = insertNum;
self.pointsArray = pointsArray;
////創(chuàng)建BezierPath
UIBezierPath *path = [UIBezierPath bezierPath];
////對數(shù)據(jù)進行處理雹顺,開始插值丹墨,為漸變色圖層提供范圍
[self makeDownPointWithInsertNum:insertNum andPointsArray:self.pointsArray withPath:path];
path.lineWidth = 0;
[path stroke];
///self.gradientLayer為漸變色層
CAShapeLayer *layer = [CAShapeLayer layer];////創(chuàng)建一個Layer層
layer.path = [path CGPath];
layer.lineCap = kCALineCapRound;
self.gradientLayer.mask = layer;/////layer的背景色選中區(qū)域
[self.layer addSublayer:self.gradientLayer];
[self setNeedsDisplay];
}
-(void)drawRect:(CGRect)rect
{
[super drawRect:rect];
UIBezierPath *path = [UIBezierPath bezierPath];
[self makeDownPointWithInsertNum:self.insertNum andPointsArray:self.pointsArray withPath:path];
[self.lineColor setStroke];
[path stroke];
}
////對數(shù)據(jù)進行插值處理 params: num參數(shù)表示插值的點數(shù),自己定嬉愧,點數(shù)越多贩挣,曲線越光滑 pointsArray參數(shù)表示要處理的所有點
- (void)makeDownPointWithInsertNum:(NSInteger)num andPointsArray:(NSArray *)pointsArray withPath:(UIBezierPath *)path
{
/*
插值法 使用說明 p1 和 p2 之間插值 要計算 p0 和 p3
其中 p0 是 p1 前面的一個點(如果p1已經(jīng)是數(shù)組里第一個點了,那p0就是p1點左下方一點,計算如例)
p3 是p2 后面的一個點(如果p2已經(jīng)是最后一個點了,那p3就是p2正右上方的點)
|
|
|
| .p2
|
|
| .p3
| .p1
|
|.p0
|
|__________________________________________________
*/
for (int i = 0; i < pointsArray.count-1; i ++) {
CGPoint p1 = CGPointFromString(pointsArray[i]);
CGPoint p0;
if (i == 0) {
p0 = CGPointMake(p1.x-2, p1.y-2);
[path moveToPoint:p1];
}else{
[path addLineToPoint:p1];
p0 = CGPointFromString(pointsArray[i-1]);
}
CGPoint p2 = CGPointFromString(pointsArray[i + 1]);
CGPoint p3 ;
if (i == pointsArray.count - 2) {
p3 = CGPointMake(p1.x+2, p1.y+2);
}else{
p3 = CGPointFromString(pointsArray[i + 2]);
}
////這個是插值算法,不講了,固定寫法没酣,因為我也不會王财,裝B裝漏了 -_-|
for (int i = 1; i <= num; i++) {
float t = i * (1.0f / num);
float tt = t * t;
float ttt = tt * t;
CGFloat pointx_x = (float) (0.5 * (2 * p1.x + (p2.x - p0.x) * t + (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * tt + (3 * p1.x - p0.x - 3 * p2.x + p3.x)
* ttt));
CGFloat pointx_y = (float) (0.5 * (2 * p1.y + (p2.y - p0.y) * t + (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * tt + (3 * p1.y - p0.y - 3 * p2.y + p3.y)
* ttt));
[path addLineToPoint:CGPointMake(pointx_x, pointx_y)];
}
}
}
#pragma mark -- getter/setter 專門負責添加漸變色
- (CAGradientLayer *)gradientLayer
{
if (!_gradientLayer) {
_gradientLayer = [CAGradientLayer layer];
_gradientLayer.frame = self.bounds;
_gradientLayer.colors = @[(__bridge id)kSetAlColor(kGetColorRed(_lineColor), kGetColorGreen(_lineColor), kGetColorBlue(_lineColor), 0.8).CGColor,(__bridge id)kSetAlColor(kGetColorRed(_lineColor), kGetColorGreen(_lineColor), kGetColorBlue(_lineColor), 0.1).CGColor];///其中漸變層的顏色種類,alpha表示所占的百分比
_gradientLayer.startPoint = CGPointMake(0, 0);///表示開始的方位(左 裕便,上)
_gradientLayer.endPoint = CGPointMake(0, 1);////結(jié)束方位(右绒净,下)
}
return _gradientLayer;
}
@end
最后是封裝的曲線類的使用
- (void)viewDidLoad {
[super viewDidLoad];
GradeColorView *colorView = [[GradeColorView alloc]initWithFrame:CGRectMake(80, 120, 250, 250)];
[colorView updateUIWithPointArray:@[NSStringFromCGPoint(CGPointMake(0,250)),NSStringFromCGPoint(CGPointMake(20, 160)),NSStringFromCGPoint(CGPointMake(40, 100)),NSStringFromCGPoint(CGPointMake(60, 20)),NSStringFromCGPoint(CGPointMake(80, 90)),NSStringFromCGPoint(CGPointMake(100, 120)),NSStringFromCGPoint(CGPointMake(120, 80)),NSStringFromCGPoint(CGPointMake(140, 140)),NSStringFromCGPoint(CGPointMake(160, 190)),NSStringFromCGPoint(CGPointMake(250, 250))] insertNum:19 withLineColor:[UIColor orangeColor]];
[self.view addSubview:colorView];
}
在下面是數(shù)組元素轉(zhuǎn)化便于數(shù)組存取的DataGetY類
.h文件
#import <Foundation/Foundation.h>
#define Str(f) [NSString stringWithFormat:@"%f",f]
@interface DataGetY : NSObject
- (NSMutableDictionary *)makeDownDataWithDataArray:(NSArray *)points;
@end
.m文件
#import "DataGetY.h"
#import <UIKit/UIKit.h>
@implementation DataGetY
- (NSMutableDictionary *)makeDownDataWithDataArray:(NSArray *)points
{
if (points.count > 0) {
NSMutableDictionary *dic;
for (NSString *pointStr in points) {
CGPoint point = CGPointFromString(pointStr);
[dic setObject:Str(point.y) forKey:Str(point.x)];
}
return dic;
}
return nil;
}
@end
下面是插值曲線的效果: