CAShapeLayer 是 CALayer 的子類(lèi)聪黎,但是比 CALayer 更靈活,可以畫(huà)出各種圖形攒菠。
別忘記引入QuartzCore.framework
樣例####
在 CAShapeLayer 中寇僧,也可以像 CALayer 一樣指定它的 frame 來(lái)畫(huà),就像這樣:
- (void) Demo01View{
CAShapeLayer *layer = [CAShapeLayer layer];
layer.frame = CGRectMake(110, 100, 150, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer];
}
Demo01View
但是妄痪,CAShapeLayer 有一個(gè)神奇的屬性 path
用這個(gè)屬性配合上 UIBezierPath 這個(gè)類(lèi)就可以達(dá)到超神的效果哈雏。
UIBezierPath 顧名思義,這是用貝塞爾曲線的方式來(lái)構(gòu)建一段弧線衫生,你可以用任意條弧線來(lái)組成你想要的形狀裳瘪,比如,你想用它來(lái)和上面一樣畫(huà)一個(gè)矩形罪针,那就可以這樣子來(lái)做:
- (void) Demo02View{
//矩形
UIBezierPath *path01 = [UIBezierPath bezierPathWithRect:CGRectMake(110, 100, 150, 100)];
CAShapeLayer *layer01 = [CAShapeLayer layer];
layer01.path = path01.CGPath;
layer01.fillColor = [UIColor clearColor].CGColor;//填充顏色 不要使用backgroundColor屬性
layer01.strokeColor = [UIColor blackColor].CGColor;//邊框顏色
[self.view.layer addSublayer:layer01];
//圓角矩形
UIBezierPath *path02 = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(110, 235, 150, 100) cornerRadius:50];
CAShapeLayer *layer02 = [CAShapeLayer layer];
layer02.path = path02.CGPath;
layer02.fillColor = [UIColor clearColor].CGColor;
layer02.strokeColor = [UIColor blackColor].CGColor;
[self.view.layer addSublayer:layer02];
//圓 順時(shí)針
CGFloat radius = 60.0;//半徑
CGFloat startAngle = 0.0;//開(kāi)始角度
CGFloat endAngle = (M_PI * 2);//結(jié)束角度
UIBezierPath *path03 = [UIBezierPath bezierPathWithArcCenter:CGPointMake([UIScreen mainScreen].bounds.size.width/2.0, 430.0) radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
CAShapeLayer *layer03 = [CAShapeLayer layer];
layer03.path = path03.CGPath;
layer03.fillColor = [UIColor clearColor].CGColor;
layer03.strokeColor = [UIColor blackColor].CGColor;
[self.view.layer addSublayer:layer03];
}
Demo02View
畫(huà)曲線####
貝塞爾曲線的畫(huà)法是由起點(diǎn)彭羹、終點(diǎn)、控制點(diǎn)三個(gè)參數(shù)來(lái)畫(huà)的泪酱,為了解釋清楚這個(gè)點(diǎn)派殷,我寫(xiě)了幾行代碼來(lái)解釋它
- (void) Demo03View{
CGPoint startPoint = CGPointMake(50, 300);
CGPoint endPoint = CGPointMake(300, 300);
CGPoint controlPoint = CGPointMake(170, 200);
CALayer *layer1 = [CALayer layer];
layer1.frame = CGRectMake(startPoint.x, startPoint.y, 5, 5);
layer1.backgroundColor = [UIColor redColor].CGColor;
CALayer *layer2 = [CALayer layer];
layer2.frame = CGRectMake(endPoint.x, endPoint.y, 5, 5);
layer2.backgroundColor = [UIColor redColor].CGColor;
CALayer *layer3 = [CALayer layer];
layer3.frame = CGRectMake(controlPoint.x, controlPoint.y, 5, 5);
layer3.backgroundColor = [UIColor redColor].CGColor;
UIBezierPath *path = [UIBezierPath bezierPath];
CAShapeLayer *layer = [CAShapeLayer layer];
[path moveToPoint:startPoint];//移動(dòng)到起始點(diǎn)
[path addQuadCurveToPoint:endPoint controlPoint:controlPoint];//結(jié)束點(diǎn)和控制點(diǎn)
//CGPoint controlPoint1 = CGPointMake(133, 200);
//CGPoint controlPoint2 = CGPointMake(216, 400);
//[path addCurveToPoint:endPoint controlPoint1:controlPoint1 controlPoint2:controlPoint2];//使用兩個(gè)控制點(diǎn)來(lái)畫(huà)
layer.path = path.CGPath;
layer.fillColor = [UIColor clearColor].CGColor;
layer.strokeColor = [UIColor blackColor].CGColor;
[self.view.layer addSublayer:layer];
[self.view.layer addSublayer:layer1];
[self.view.layer addSublayer:layer2];
[self.view.layer addSublayer:layer3];
}
Demo03View
CAShapeLayer動(dòng)畫(huà)###
動(dòng)畫(huà)使用 strokeEnd strokeStart lineWidth三個(gè)屬性
// layer是貝塞爾曲線
// 線從開(kāi)始點(diǎn)到結(jié)束點(diǎn)逐漸顯示
- (void) animation01:(CAShapeLayer *)layer{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath: @"strokeEnd"];
animation.fromValue = @0;
animation.toValue = @1;
animation.duration = 2.0;
[layer addAnimation:animation forKey:@""];
}
// 線從中間向兩邊逐漸顯示
- (void) animation02:(CAShapeLayer *)layer{
layer.strokeStart = 0.5;
layer.strokeEnd = 0.5;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
animation.fromValue = @0.5;
animation.toValue = @0;
animation.duration = 2.0;
CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath: @"strokeEnd"];
animation2.fromValue = @(0.5);
animation2.toValue = @1;
animation2.duration = 2.0;
[layer addAnimation:animation forKey:@""];
[layer addAnimation:animation2 forKey:@""];
}
// 線條變粗
- (void) animation03:(CAShapeLayer *)layer{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath: @"lineWidth"];
animation.fromValue = @1;
animation.toValue = @10;
animation.duration = 2.0;
[layer addAnimation:animation forKey:@""];
}
- (void) Demo04View{
CGSize finalSize = CGSizeMake(CGRectGetWidth(self.view.frame), 400);
CGFloat layerHeight = finalSize.height * 0.2;
CAShapeLayer *layer = [CAShapeLayer layer];
UIBezierPath *bezier = [UIBezierPath bezierPath];
[bezier moveToPoint:CGPointMake(0, finalSize.height - layerHeight)];
[bezier addLineToPoint:CGPointMake(0, finalSize.height - 1)];
[bezier addLineToPoint:CGPointMake(finalSize.width, finalSize.height - 1)];
[bezier addLineToPoint:CGPointMake(finalSize.width, finalSize.height - layerHeight)];
[bezier addQuadCurveToPoint:CGPointMake(0,finalSize.height - layerHeight) controlPoint:CGPointMake(finalSize.width / 2, (finalSize.height - layerHeight) - 40)];
layer.path = bezier.CGPath;
layer.fillColor = [UIColor blackColor].CGColor;
[self.view.layer addSublayer:layer];
//描點(diǎn)
CALayer *layer1 = [CALayer layer];
layer1.frame = CGRectMake(0, finalSize.height - layerHeight, 5, 5);
layer1.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer1];
CALayer *layer2 = [CALayer layer];
layer2.frame = CGRectMake(0, finalSize.height - 1, 5, 5);
layer2.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer2];
CALayer *layer3 = [CALayer layer];
layer3.frame = CGRectMake(finalSize.width-5, finalSize.height - 1, 5, 5);
layer3.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer3];
CALayer *layer4 = [CALayer layer];
layer4.frame = CGRectMake(finalSize.width-5, finalSize.height - layerHeight, 5, 5);
layer4.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer4];
CALayer *layer5 = [CALayer layer];
layer5.frame = CGRectMake(finalSize.width / 2, (finalSize.height - layerHeight) - 40, 5, 5);
layer5.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer5];
}
Demo04View
應(yīng)用###
微信小眼睛
.h文件
#import <UIKit/UIKit.h>
@interface WXPullView : UIView
- (void)animationWith:(CGFloat)y;
@end
.m文件
#import "WXPullView.h"
@interface WXPullView ()
@property (strong, nonatomic) CAShapeLayer *eyeFirstLightLayer;
@property (strong, nonatomic) CAShapeLayer *eyeSecondLightLayer;
@property (strong, nonatomic) CAShapeLayer *eyeballLayer;
@property (strong, nonatomic) CAShapeLayer *topEyesocketLayer;
@property (strong, nonatomic) CAShapeLayer *bottomEyesocketLayer;
@end
@implementation WXPullView
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self.layer addSublayer:self.eyeFirstLightLayer];
[self.layer addSublayer:self.eyeSecondLightLayer];
[self.layer addSublayer:self.eyeballLayer];
[self.layer addSublayer:self.topEyesocketLayer];
[self.layer addSublayer:self.bottomEyesocketLayer];
[self setupAnimation];
}
return self;
}
- (CAShapeLayer *)eyeFirstLightLayer {
if (!_eyeFirstLightLayer) {
_eyeFirstLightLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:CGRectGetWidth(self.frame) * 0.2 startAngle:(230.f / 180.f) * M_PI endAngle:(265.f / 180.f) * M_PI clockwise:YES];
_eyeFirstLightLayer.borderColor = [UIColor blackColor].CGColor;
_eyeFirstLightLayer.lineWidth = 5.f;
_eyeFirstLightLayer.path = path.CGPath;
_eyeFirstLightLayer.fillColor = [UIColor clearColor].CGColor;
_eyeFirstLightLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _eyeFirstLightLayer;
}
- (CAShapeLayer *)eyeSecondLightLayer {
if (!_eyeSecondLightLayer) {
_eyeSecondLightLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:CGRectGetWidth(self.frame) * 0.2 startAngle:(211.f / 180.f) * M_PI endAngle:(220.f / 180.f) * M_PI clockwise:YES];
_eyeSecondLightLayer.borderColor = [UIColor blackColor].CGColor;
_eyeSecondLightLayer.lineWidth = 5.f;
_eyeSecondLightLayer.path = path.CGPath;
_eyeSecondLightLayer.fillColor = [UIColor clearColor].CGColor;
_eyeSecondLightLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _eyeSecondLightLayer;
}
- (CAShapeLayer *)eyeballLayer {
if (!_eyeballLayer) {
_eyeballLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:CGRectGetWidth(self.frame) * 0.3 startAngle:(0.f / 180.f) * M_PI endAngle:(360.f / 180.f) * M_PI clockwise:YES];
_eyeballLayer.borderColor = [UIColor blackColor].CGColor;
_eyeballLayer.lineWidth = 1.f;
_eyeballLayer.path = path.CGPath;
_eyeballLayer.fillColor = [UIColor clearColor].CGColor;
_eyeballLayer.strokeColor = [UIColor whiteColor].CGColor;
_eyeballLayer.anchorPoint = CGPointMake(0.5, 0.5);
}
return _eyeballLayer;
}
- (CAShapeLayer *)topEyesocketLayer {
if (!_topEyesocketLayer) {
_topEyesocketLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, CGRectGetHeight(self.frame) / 2)];
[path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) / 2) controlPoint:CGPointMake(CGRectGetWidth(self.frame) / 2, center.y - center.y - 20)];
_topEyesocketLayer.borderColor = [UIColor blackColor].CGColor;
_topEyesocketLayer.lineWidth = 1.f;
_topEyesocketLayer.path = path.CGPath;
_topEyesocketLayer.fillColor = [UIColor clearColor].CGColor;
_topEyesocketLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _topEyesocketLayer;
}
- (CAShapeLayer *)bottomEyesocketLayer {
if (!_bottomEyesocketLayer) {
_bottomEyesocketLayer = [CAShapeLayer layer];
CGPoint center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) / 2);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(0, CGRectGetHeight(self.frame) / 2)];
[path addQuadCurveToPoint:CGPointMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame) / 2) controlPoint:CGPointMake(CGRectGetWidth(self.frame) / 2, center.y + center.y + 20)];
_bottomEyesocketLayer.borderColor = [UIColor blackColor].CGColor;
_bottomEyesocketLayer.lineWidth = 1.f;
_bottomEyesocketLayer.path = path.CGPath;
_bottomEyesocketLayer.fillColor = [UIColor clearColor].CGColor;
_bottomEyesocketLayer.strokeColor = [UIColor whiteColor].CGColor;
}
return _bottomEyesocketLayer;
}
- (void)setupAnimation {
self.eyeFirstLightLayer.lineWidth = 0.f;
self.eyeSecondLightLayer.lineWidth = 0.f;
self.eyeballLayer.opacity = 0.f;
_bottomEyesocketLayer.strokeStart = 0.5f;
_bottomEyesocketLayer.strokeEnd = 0.5f;
_topEyesocketLayer.strokeStart = 0.5f;
_topEyesocketLayer.strokeEnd = 0.5f;
}
- (void)animationWith:(CGFloat)y {
CGFloat flag = self.frame.origin.y * 2.f - 20.f;
if (y < flag) {
if (self.eyeFirstLightLayer.lineWidth < 5.f) {
self.eyeFirstLightLayer.lineWidth += 1.f;
self.eyeSecondLightLayer.lineWidth += 1.f;
}
}
if(y < flag - 20) {
if (self.eyeballLayer.opacity <= 1.0f) {
self.eyeballLayer.opacity += 0.1f;
}
}
if (y < flag - 40) {
if (self.topEyesocketLayer.strokeEnd < 1.f && self.topEyesocketLayer.strokeStart > 0.f) {
self.topEyesocketLayer.strokeEnd += 0.1f;
self.topEyesocketLayer.strokeStart -= 0.1f;
self.bottomEyesocketLayer.strokeEnd += 0.1f;
self.bottomEyesocketLayer.strokeStart -= 0.1f;
}
}
if (y > flag - 40) {
if (self.topEyesocketLayer.strokeEnd > 0.5f && self.topEyesocketLayer.strokeStart < 0.5f) {
self.topEyesocketLayer.strokeEnd -= 0.1f;
self.topEyesocketLayer.strokeStart += 0.1f;
self.bottomEyesocketLayer.strokeEnd -= 0.1f;
self.bottomEyesocketLayer.strokeStart += 0.1f;
}
}
if (y > flag - 20) {
if (self.eyeballLayer.opacity >= 0.0f) {
self.eyeballLayer.opacity -= 0.1f;
}
}
if (y > flag) {
if (self.eyeFirstLightLayer.lineWidth > 0.f) {
self.eyeFirstLightLayer.lineWidth -= 1.f;
self.eyeSecondLightLayer.lineWidth -= 1.f;
}
}
}
@end
微信小眼睛WXPullView.gif
彩虹進(jìn)度條
.h文件
#import <UIKit/UIKit.h>
@interface RainbowProgress : UIView
//Progress 高度
@property (nonatomic,assign)CGFloat progressHeigh;
//Progress Value (0~1)
@property (nonatomic,assign)CGFloat progressValue;
/** 開(kāi)始動(dòng)畫(huà)過(guò)程 */
- (void)startAnimating;
/** 結(jié)束動(dòng)畫(huà)過(guò)程 */
- (void)stopAnimating;
.m文件
#import "RainbowProgress.h"
@interface RainbowProgress ()<CAAnimationDelegate>
/** Animating */
@property (nonatomic,assign,getter=isAnimating)BOOL animating;
/** CAShapeLayer */
@property (nonatomic,weak)CAShapeLayer *shapeMaskLayer;
@end
@implementation RainbowProgress
#pragma mark - 將UIView默認(rèn)的CALayer替換成CAGradientLayer
+(Class)layerClass{
return [CAGradientLayer class];
}
#pragma mark - 初始化方法
- (instancetype)initWithFrame:(CGRect)frame{
CGRect originFrame = CGRectMake(0, self.progressHeigh, [UIScreen mainScreen].bounds.size.width, 2);
self = [super initWithFrame:frame];
if (self) {
self.frame = originFrame;
[self setUpRainbowLayer];
}
return self;
}
-(void)setUpRainbowLayer{
// 1、創(chuàng)建CAGradientLayer彩虹條顏色層墓阀,彩虹顏色當(dāng)然需要數(shù)組存儲(chǔ)
CAGradientLayer* gradientLayer = (CAGradientLayer*)self.layer;
[gradientLayer setStartPoint:CGPointMake(0, 0)];
[gradientLayer setEndPoint:CGPointMake(1, 0.01)];
//gradientLayer.locations = @[@(0.001),@(0.001),@(0.001)];
NSMutableArray *rainBowColors = [NSMutableArray array];
for (NSInteger hue = 0; hue <= 360; hue += 5) {
UIColor *color = [UIColor colorWithHue:1.0*hue/360.0
saturation:1.0
brightness:1.0
alpha:1.0];
[rainBowColors addObject:(id)color.CGColor];
}
gradientLayer.colors = [NSArray arrayWithArray:rainBowColors];
// 2愈腾、創(chuàng)建遮罩層 同時(shí)也需要貝塞爾曲線
UIBezierPath* shapePath = [UIBezierPath bezierPath];
[shapePath moveToPoint:CGPointMake(0, 0)];
[shapePath addLineToPoint:CGPointMake(self.bounds.size.width, 0)];
CAShapeLayer* shapeMaskLayer = [CAShapeLayer layer];
shapeMaskLayer.path = shapePath.CGPath;
shapeMaskLayer.lineWidth = 4.f;
shapeMaskLayer.fillColor = [UIColor clearColor].CGColor;
shapeMaskLayer.strokeColor = [UIColor blackColor].CGColor;
// 設(shè)置shapeMaskLayer的起止點(diǎn)初始值均為0
shapeMaskLayer.strokeStart = 0;
shapeMaskLayer.strokeEnd = 0;
gradientLayer.mask = shapeMaskLayer;
self.shapeMaskLayer = shapeMaskLayer;
}
#pragma mark - 執(zhí)行動(dòng)畫(huà)的過(guò)程
-(void)performAnimation{
// Update the colors on the model layer
CAGradientLayer *layer = (id)[self layer];
NSArray *fromColors = [layer colors];
NSArray *toColors = [self shiftColors:fromColors];
[layer setColors:toColors];
// Create an animation to slowly move the hue gradient left to right.
CABasicAnimation *animation;
animation = [CABasicAnimation animationWithKeyPath:@"colors"];
[animation setFromValue:fromColors];
[animation setToValue:toColors];
[animation setDuration:0.08]; // CALayer的color切換時(shí)間是0.08
[animation setRemovedOnCompletion:YES]; // 動(dòng)畫(huà)完成后是否要移除
[animation setFillMode:kCAFillModeForwards];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
[animation setDelegate:self];
// Add the animation to our layer
[layer addAnimation:animation forKey:@"animateGradient"];
}
/*
當(dāng)動(dòng)畫(huà)在活動(dòng)時(shí)間內(nèi)完成或者是從層對(duì)象中移除這個(gè)代理方法會(huì)被調(diào)用,如果動(dòng)畫(huà)直到它的活動(dòng)時(shí)間末尾沒(méi)有被移除岂津,那這個(gè)'flag'是true的虱黄。
回調(diào)和布爾值來(lái)保證動(dòng)畫(huà)的循環(huán)開(kāi)始并持續(xù)以及結(jié)束該動(dòng)畫(huà)
*/
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
// 當(dāng)動(dòng)畫(huà)在duration時(shí)間結(jié)束前移除了,這個(gè)方法會(huì)被調(diào)用
// 然后就下面的if語(yǔ)句判斷吮成,如果isAnimation = yes橱乱,就重新執(zhí)行performAnimation
// 在這個(gè)performAnimation中重新創(chuàng)建了核心動(dòng)畫(huà)對(duì)象辜梳,重新設(shè)置了代理
if ([self isAnimating]) {
[self performAnimation];
}
}
- (void)startAnimating {
if (![self isAnimating]) {
self.animating = YES;
[self performAnimation];
}
}
- (void)stopAnimating {
if ([self isAnimating]) {
self.animating = NO;
}
}
#pragma mark - 輔助方法:轉(zhuǎn)移可變數(shù)組最后一個(gè)元素到數(shù)組的最前面
- (NSArray *)shiftColors:(NSArray *)colors {
// Moves the last item in the array to the front
// shifting all the other elements.
// 數(shù)組中最后一項(xiàng)移動(dòng)到前面
// 轉(zhuǎn)移的所有其他元素
NSMutableArray *mutable = [colors mutableCopy];// 將NSArray數(shù)組換成 NSMutableArray
id last = [mutable lastObject]; // 單獨(dú)取出最后一個(gè)元素
[mutable removeLastObject]; // 然后將數(shù)組中的最后一個(gè)元素去除
[mutable insertObject:last atIndex:0]; // 然后將取出的元素插入到最前面
return [NSArray arrayWithArray:mutable];
}
#pragma mark - 重寫(xiě)set和get方法
// 重設(shè)進(jìn)度條在父控件的高度位置
@synthesize progressHeigh = _progressHeigh;
-(void)setProgressHeigh:(CGFloat)progressHeigh{
_progressHeigh = progressHeigh;
// 就要重新設(shè)置RainbowProgress這個(gè)自定義UIView的高度
CGRect frame = self.frame;
frame.origin.y = _progressHeigh;
self.frame = frame;
}
-(CGFloat)progressHeigh{
if (!_progressHeigh) {
_progressHeigh = 22;
}
return _progressHeigh;
}
// 設(shè)置進(jìn)度條的值
@synthesize progressValue = _progressValue;
-(void)setProgressValue:(CGFloat)progressValue{
progressValue = progressValue > 1 ? 1 : progressValue;
progressValue = progressValue < 0 ? 0 : progressValue;
_progressValue = progressValue;
self.shapeMaskLayer.strokeEnd = _progressValue;
}
-(CGFloat)progressValue{
return _progressValue;
}
@end
彩虹進(jìn)度條 RainbowProgress.gif