版本记录
| 版本号 | 时间 |
|---|---|
| V1.0 | 2017.08.08 |
前言
quartz是一个通用的术语,用于描述在iOS和MAC OS X中整个媒体层用到的多种技术 包括图形、动画、音频、适配。Quart 2D是一组二维绘图和渲染API,Core Graphic会使用到这组API,Quartz Core专指Core Animation用到的动画相关的库、API和类。CoreGraphics是UIKit下的主要绘图系统,频繁的用于绘制自定义视图。Core Graphics是高度集成于UIView和其他UIKit部分的。Core Graphics数据结构和函数可以通过前缀CG来识别。在app中很多时候绘图等操作我们要利用CoreGraphic框架,它能绘制字符串、图形、渐变色等等,是一个很强大的工具。感兴趣的可以看我另外几篇。
1. CoreGraphic框架解析(一)—— 基本概览
2. CoreGraphic框架解析(二)—— 基本使用
功能要求
实现波浪线的海浪效果,比如中国联通客户端顶部剩余流量的波浪线。

效果图
功能实现
下面还是直接看代码。
1. JJCoreGraphicWaveVC.m
#import "JJCoreGraphicWaveVC.h"
#import "JJCoreGraphicWaveView.h"
#import "Masonry.h"
@interface JJCoreGraphicWaveVC ()
@end
@implementation JJCoreGraphicWaveVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.title = @"CoreGraphic实现波浪线";
//加载波浪线视图
JJCoreGraphicWaveView *waveView = [[JJCoreGraphicWaveView alloc] init];
[self.view addSubview:waveView];
[waveView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.width.equalTo(@300);
make.height.equalTo(@200);
}];
}
@end
2. JJCoreGraphicWaveView.m
#import "JJCoreGraphicWaveView.h"
#define kJJCoreGraphicWaveViewScreenWidth [UIScreen mainScreen].bounds.size.width
#define kJJCoreGraphicWaveViewScreenHeight [UIScreen mainScreen].bounds.size.height
@interface JJCoreGraphicWaveView ()
@property (nonatomic, strong) UIColor *waterColor;
@property (nonatomic, assign) CGFloat waterLineY;
@property (nonatomic, assign) CGFloat waveAmplitude;
@property (nonatomic, assign) CGFloat waveCycle;
@property (nonatomic, assign) BOOL isIncrease;
@property (nonatomic, strong) CADisplayLink *waveDisplayLink;
@end
@implementation JJCoreGraphicWaveView
#pragma mark - Override Base Function
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setInitConfig];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
//初始化画布
CGContextRef context = UIGraphicsGetCurrentContext();
//推入
CGContextSaveGState(context);
//定义前波浪path
CGMutablePathRef frontPath = CGPathCreateMutable();
//定义后波浪path
CGMutablePathRef backPath = CGPathCreateMutable();
//定义前波浪反色path
CGMutablePathRef frontReversePath = CGPathCreateMutable();
//定义后波浪反色path
CGMutablePathRef backReversePath = CGPathCreateMutable();
//画水
CGContextSetLineWidth(context, 1);
//前波浪位置初始化
float frontY = self.waterLineY;
CGPathMoveToPoint(frontPath, NULL, 0, frontY);
//前波浪反色位置初始化
float frontReverseY = self.waterLineY;
CGPathMoveToPoint(frontReversePath, NULL, 0,frontReverseY);
//后波浪位置初始化
float backY = self.waterLineY;
CGPathMoveToPoint(backPath, NULL, 0, backY);
//后波浪反色位置初始化
float backReverseY = self.waterLineY;
CGPathMoveToPoint(backReversePath, NULL, 0, backReverseY);
for(float x = 0; x <= kJJCoreGraphicWaveViewScreenWidth; x ++){
//前波浪绘制
frontY= _waveAmplitude * sin( x/180 * M_PI + 4 * self.waveCycle/M_PI ) * 5 + self.waterLineY;
CGPathAddLineToPoint(frontPath, nil, x, frontY);
//后波浪绘制
backY= _waveAmplitude * cos( x/180 * M_PI + 3 * self.waveCycle/M_PI ) * 5 + self.waterLineY;
CGPathAddLineToPoint(backPath, nil, x, backY);
if (x>=100) {
//后波浪反色绘制
backReverseY= _waveAmplitude * cos( x/180 * M_PI + 3 * self.waveCycle/M_PI ) * 5 + self.waterLineY;
CGPathAddLineToPoint(backReversePath, nil, x, backReverseY);
//前波浪反色绘制
frontReverseY= _waveAmplitude * sin( x/180 * M_PI + 4 * self.waveCycle/M_PI ) * 5 + self.waterLineY;
CGPathAddLineToPoint(frontReversePath, nil, x, frontReverseY);
}
}
//后波浪绘制
CGContextSetFillColorWithColor(context, [UIColor greenColor].CGColor);
CGPathAddLineToPoint(backPath, nil, kJJCoreGraphicWaveViewScreenWidth, rect.size.height);
CGPathAddLineToPoint(backPath, nil, 0, rect.size.height);
CGPathAddLineToPoint(backPath, nil, 0, self.waterLineY);
CGPathCloseSubpath(backPath);
CGContextAddPath(context, backPath);
CGContextFillPath(context);
//推入
CGContextSaveGState(context);
//后波浪反色绘制
CGPathAddLineToPoint(backReversePath, nil, kJJCoreGraphicWaveViewScreenWidth, rect.size.height);
CGPathAddLineToPoint(backReversePath, nil, 100, rect.size.height);
CGPathAddLineToPoint(backReversePath, nil, 100, self.waterLineY);
CGContextAddPath(context, backReversePath);
CGContextClip(context);
//弹出
CGContextRestoreGState(context);
//前波浪绘制
CGContextSetFillColorWithColor(context, [_waterColor CGColor]);
CGPathAddLineToPoint(frontPath, nil, kJJCoreGraphicWaveViewScreenWidth, rect.size.height);
CGPathAddLineToPoint(frontPath, nil, 0, rect.size.height);
CGPathAddLineToPoint(frontPath, nil, 0, self.waterLineY);
CGPathCloseSubpath(frontPath);
CGContextAddPath(context, frontPath);
CGContextFillPath(context);
//推入
CGContextSaveGState(context);
//前波浪反色绘制
CGPathAddLineToPoint(frontReversePath, nil, kJJCoreGraphicWaveViewScreenWidth, rect.size.height);
CGPathAddLineToPoint(frontReversePath, nil, 100, rect.size.height);
CGPathAddLineToPoint(frontReversePath, nil, 100, self.waterLineY);
CGContextAddPath(context, frontReversePath);
CGContextClip(context);
//推入
CGContextSaveGState(context);
//释放
CGPathRelease(backPath);
CGPathRelease(backReversePath);
CGPathRelease(frontPath);
CGPathRelease(frontReversePath);
}
#pragma mark - Object Private Function
- (void)setInitConfig
{
self.backgroundColor = [UIColor clearColor];
self.waveAmplitude = 3.0;
self.waveCycle = 1.0;
self.waterColor = [UIColor colorWithRed:90/255.0 green:200/255.0 blue:140/255.0 alpha:1.0];
self.waterLineY = 20.0;
self.waveDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(waveDidRun)];
[self.waveDisplayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}
#pragma mark - Action && Notification
//CADisplayLink,每秒60次刷新界面
- (void)waveDidRun
{
if (self.isIncrease) {
self.waveAmplitude += 0.03;
}
else {
self.waveAmplitude -= 0.03;
}
if (self.waveAmplitude <= 1) {
self.isIncrease = YES;
}
if (self.waveAmplitude >= 1.5) {
self.isIncrease = NO;
}
//速度控制
self.waveCycle += 0.02;
//调用drawRect方法不停的绘制
[self setNeedsDisplay];
}
@end
还有几点要说明下:
-
CADisplayLink频率是每秒钟更新60次,更新速度很快。 -
JJCoreGraphicWaveView必须给布局和大小frame,否则- (void)drawRect:(CGRect)rect方法是不会调用的。
功能效果
下面我们就看一下功能效果。

效果展示1

效果展示2

动图展示
参考文章
后记
未完,待续~~~

秋