版本记录
版本号 | 时间 |
---|---|
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. iOS双波浪动画解析
2. iOS 动画-波浪
后记
未完,待续~~~