quartz 2d的知识我总是容易忘记,在这里打算花点时间整理一下,对自己和对大家都是有好处的,如果我有什么不对或者不全的地方 请大家给予指正,鄙人不胜感激。
画一条直线
绘图的基本步骤
- 创建上下文(这个必须在drawRect方法才可以 ,默认view 调用一次,每次调用setNeedsDisplay 它会调用一次)
- 对- (void)drawRect:(CGRect)rect说明
1.调用时机:是在view加载完毕的时候开始调用
2.rect 就是view的bounds
3.用来专门绘制上下文的 - 上下文步骤的详细说明
1.创建上下文
2.创建路径
3.将路径添加到上下文
4.开始绘制 - 画一条直线的详细代码
- (void)drawRect:(CGRect)rect {
// 获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 创建路径
UIBezierPath *path = [[UIBezierPath alloc] init];
// 创建起点
[path moveToPoint:CGPointMake(10, 100)];
// 创建终点
[path addLineToPoint:CGPointMake(100, 10)];
// 在加上一个终点
[path addLineToPoint:CGPointMake(180, 100)];
// 设置线宽
CGContextSetLineWidth(ctx, 10);
// 设置颜色
[[UIColor greenColor] setStroke];
// 添加圆角(在两条线连接的地方)
CGContextSetLineJoin(ctx, kCGLineJoinRound);
// 设置两条线的尾部的圆角
CGContextSetLineCap(ctx, kCGLineCapRound);
// 将路径添加到上下文上
CGContextAddPath(ctx, path.CGPath);
// 进行绘制
CGContextStrokePath(ctx);
}
- 画一条曲线
- (void)drawRect:(CGRect)rect {
// 获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 创建路径
UIBezierPath *path = [[UIBezierPath alloc] init];
//创建起始点
[path moveToPoint:CGPointMake(10, 100)];
// 画曲线
[path addQuadCurveToPoint:CGPointMake(180, 100) controlPoint:CGPointMake(100, 0)];
// 设置颜色
[[UIColor greenColor] setStroke];
// 设置线宽
CGContextSetLineWidth(ctx, 10);
// 设置两条线的尾部的圆角
CGContextSetLineCap(ctx, kCGLineCapRound);
// 将路径添加到上下文上
CGContextAddPath(ctx, path.CGPath);
// 进行绘制
CGContextStrokePath(ctx);
}
- 画一个长方形或者正方形
- (void)drawRect:(CGRect)rect {
// 用这个方法创建的时候已经默认创建了上下文
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 100, 100)];
// 设置四个角的样式
path.lineJoinStyle = kCGLineJoinRound;
// 设置颜色
[[UIColor greenColor] setStroke];
// 设置边角宽度
path.lineWidth = 10.0;
// 开始绘制
[path stroke];
}
- 画一个圆形
- (void)drawRect:(CGRect)rect {
// 用这个方法创建的时候已经默认创建了上下文
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(10, 10, 100, 100) cornerRadius:50];
// 设置四个角的样式
path.lineJoinStyle = kCGLineJoinRound;
// 设置颜色
[[UIColor greenColor] setStroke];
// 设置边角宽度
path.lineWidth = 10.0;
// 开始绘制
[path stroke];
}
- 画一个实心圆 用另外的一种方法
- (void)drawRect:(CGRect)rect {
// 创建上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// frame
CGRect frame = CGRectMake(10, 10, 100, 100);
// 设置颜色
[[UIColor greenColor] set];
// 画一个圆形的区域
CGContextAddEllipseInRect(ctx, frame);
// 开始绘制
CGContextFillPath(ctx);
}
- 画一个椭圆(空心的)
- (void)drawRect:(CGRect)rect {
// 创建路径
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 180, 100)];
// 设置宽度
path.lineWidth = 10;
// 设置颜色
[[UIColor greenColor] setStroke];
// 开始绘制
[path stroke];
}
- 画一个实心的椭圆
/**
画一个实心的椭圆
*/
- (void)drawRealOval {
// 创建路径
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 180, 100)];
// 设置颜色
[[UIColor greenColor] setFill];
// 开始绘制
[path fill];
}
- 画一个空心的圆弧
/**
画一个空心的圆弧
*/
-(void)drawArc {
// 开始的角度
CGFloat startA = -M_PI_2;
// 结束的角度
CGFloat endA = M_PI_2;
// 开始创建路径(clockwise : yes 是顺时针 no:逆时针)
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:80 startAngle:startA endAngle:endA clockwise:YES];
// 设置颜色
[[UIColor greenColor] setStroke];
// 宽度
path.lineWidth = 10;
// 开始绘制
[path stroke];
}
- 画一个实心的圆弧
/**
画一个实心的圆弧
*/
- (void)drawRealArc {
// 开始的角度
CGFloat startA = -M_PI_2;
// 结束的角度
CGFloat endA = M_PI_2;
// 开始创建路径(clockwise : yes 是顺时针 no:逆时针)
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100) radius:80 startAngle:startA endAngle:endA clockwise:YES];
// 设置颜色
[[UIColor greenColor] setFill];
// 开始绘制
[path fill];
}
- 画一个字符串( [str drawAtPoint:CGPointZero withAttributes:dic];其中它与 [str drawInRect:rect withAttributes:dic]的区别是drawInRect:rect可以换行的)
- (void)drawRect:(CGRect)rect {
NSString *str = @"哈哈哈哈";
NSShadow *shadow = [[NSShadow alloc] init];
// 宽高的偏移
shadow.shadowOffset = CGSizeMake(10, 10);
// 暗影颜色
shadow.shadowColor = [UIColor greenColor];
// 模糊
shadow.shadowBlurRadius = 5;
NSDictionary *dic = @{
NSFontAttributeName:[UIFont systemFontOfSize:30],
NSForegroundColorAttributeName : [UIColor whiteColor],
NSShadowAttributeName : shadow
};
[str drawAtPoint:CGPointZero withAttributes:dic];
}
- 画文字 2( [str drawInRect:rect withAttributes:dic];)
- (void)drawRect:(CGRect)rect {
NSString *str = @"哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈";
NSShadow *shadow = [[NSShadow alloc] init];
// 宽高的偏移
shadow.shadowOffset = CGSizeMake(10, 10);
// 暗影颜色
shadow.shadowColor = [UIColor greenColor];
// 模糊
shadow.shadowBlurRadius = 5;
NSDictionary *dic = @{
NSFontAttributeName:[UIFont systemFontOfSize:30],
NSForegroundColorAttributeName : [UIColor whiteColor],
NSShadowAttributeName : shadow
};
[str drawInRect:rect withAttributes:dic];
}
- image的绘制
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:@"1"];
// 这个可以把一整张图片显示完全
[image drawInRect:rect];
}
- image的另外一个显示方法
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:@"1"];
// 显示不完全 按照实际的比例进行显示
[image drawAtPoint:CGPointZero];
}
- image 平铺的方式
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed:@"美眉"];
// 显示不完全 按照实际的比例进行显示
[image drawAsPatternInRect:rect];
}
- 接下来模仿一下系统的imageview的方法,具体代码我会写详细的注释,为了自己以后忘记的时候能够回来看看
1)写一个自定义的view(LDGImageView.h 文件)
#import <UIKit/UIKit.h>
@interface LDGImageView : UIView
/** image*/
@property (nonatomic, strong) UIImage *image;
/**
初始化
@param image image
@return 对象本身
*/
- (instancetype)initWithImage:(UIImage *)image;
@end
2)LDGImageView.m 文件
#import "LDGImageView.h"
@implementation LDGImageView
-(void)setImage:(UIImage *)image {
_image = image;
[self setNeedsDisplay];
}
/**
初始化
@param image image
@return 对象本身
*/
- (instancetype)initWithImage:(UIImage *)image {
if (self = [super init]) {
self.image = image;
self.frame = CGRectMake(0, 0, image.size.width, image.size.height);
[self setNeedsDisplay];
}
return self;
}
- (void)drawRect:(CGRect)rect {
[self.image drawInRect:rect];
}
3)viewController的使用
3.1)普通方法的调用
LDGImageView *imageView = [[LDGImageView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
imageView.image = [UIImage imageNamed:@"1"];
[self.view addSubview:imageView];
3.2) initimage方法的调用
LDGImageView *imageView = [[LDGImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
[self.view addSubview:imageView];
3.3) 切换image也是可以的,这里不做演示了。
- 图形上下文的状态栈
- (void)drawRect:(CGRect)rect {
// 创建上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 创建路径
UIBezierPath *path = [UIBezierPath bezierPath];
// 创建一条直线
[path moveToPoint:CGPointMake(10, 100)];
[path addLineToPoint:CGPointMake(190, 100)];
// 将当前的上下文添加到上下文的栈里
CGContextSaveGState(ctx);
// 设置颜色和宽度
[[UIColor greenColor] setStroke];
CGContextSetLineWidth(ctx, 10);
// 将路径添加到上下文上
CGContextAddPath(ctx, path.CGPath);
// 开始绘制
CGContextStrokePath(ctx);
// 从新初始化路径
path = [UIBezierPath bezierPath];
// 恢复最开始的状态
CGContextRestoreGState(ctx);
// 绘制路径
[path moveToPoint:CGPointMake(100, 10)];
[path addLineToPoint:CGPointMake(100, 190)];
// 设置颜色和宽度
[[UIColor blueColor] setStroke];
CGContextSetLineWidth(ctx, 5);
// 将路径添加到上下文上
CGContextAddPath(ctx, path.CGPath);
// 开始绘制
CGContextStrokePath(ctx);
}
- 图形上下文的矩阵操作
1.1) 平移
- (void)drawRect:(CGRect)rect {
// 创建上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 创建一个实心圆
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 50, 50)];
// 设置颜色
[[UIColor greenColor] setFill];
// 平移
CGContextTranslateCTM(ctx, 100, 120);
// 开始绘制
[path fill];
}
1.2)旋转
- (void)drawRect:(CGRect)rect {
// 创建上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 创建一个实心圆
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 100, 50)];
// 设置颜色
[[UIColor greenColor] setFill];
// 旋转
CGContextRotateCTM(ctx, M_PI_4);
// 开始绘制
[path fill];
}
1.3)缩放大小
- (void)drawRect:(CGRect)rect {
// 创建上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 创建一个实心圆
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 100, 50)];
// 设置颜色
[[UIColor greenColor] setFill];
// 缩放
CGContextScaleCTM(ctx, 2.0, 2.0);
// 开始绘制
[path fill];
}
- 一个图片水印的例子,不用在drawrect方法里边实现了
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 开启图片上下文
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 0.0);
// 创建image
UIImage *image = [UIImage imageNamed:@"美眉"];
[image drawInRect:CGRectMake(0, 0, 200, 200)];
// 创建logo文字
NSString *str = @"阿斯顿哈说的";
[str drawAtPoint:CGPointMake(20, 20) withAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12.0],
NSForegroundColorAttributeName :[UIColor redColor]
}];
// 获得上下文生成的图片
UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
// 结束当前图片上下文
UIGraphicsEndImageContext();
self.displayImageView.image = getImage;
}
- 一个带有边框的圆形片的裁剪(给image加的分类)
/**
裁剪一个图片为圆形
@param borderWidth 边框宽度
@param borderColor 边框颜色
@param imageViewWidth 外面的imageview的宽度,如果为0 将按照比例显示不按照正确的显示,如果imageview不是正方形请按照最小的传递
@param imageName 图片的名字
@return 想要的图片
*/
+(UIImage *)imageWithBorderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor imageViewWidth:(CGFloat)imageViewWidth imageName:(NSString *)imageName {
if (imageName.length == 0) {
return nil;
}
UIImage *image = [UIImage imageNamed:imageName];
CGFloat imageWidth = image.size.width;
CGFloat imageHeight = image.size.height;
imageWidth < imageHeight ? (imageHeight = imageWidth) : (imageWidth = imageHeight);
// 这里为了精确显示传入进来的borderwidth,计算比例
if (imageViewWidth > 0) {
CGFloat scale = 1.0 * (imageWidth + 2*borderWidth)/imageViewWidth;
if (scale < 1.0) {
scale = 1.0 * imageWidth/imageViewWidth;
}
borderWidth = scale * borderWidth;
}
// 创建图片上下文
UIGraphicsBeginImageContextWithOptions(CGSizeMake(imageWidth + 2*borderWidth, imageHeight + 2*borderWidth), NO, 0.0);
// 创建外面的大圆
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, imageWidth + 2*borderWidth, imageHeight + 2*borderWidth)];
// 绘制颜色
[borderColor set];
// 填写
[path fill];
// 创建小圆
CGRect rect = CGRectMake(borderWidth, borderWidth, imageWidth, imageHeight);
path = [UIBezierPath bezierPathWithOvalInRect:rect];
// 添加裁剪
[path addClip];
// 图片绘制
[image drawInRect:rect];
// 获取新的图片
UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
// 关闭图片上下文
UIGraphicsEndImageContext();
return getImage;
}
- 截屏
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 开启图片上下文
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
// 获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 进行绘制
[self.view.layer renderInContext:ctx];
// 获取图片
UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
// 保持原比例
NSData *data = UIImageJPEGRepresentation(getImage, 1.0);
[data writeToFile:@"/Users/apple/Desktop/l.jpg" atomically:YES];
}
- 图片截屏
/**
拖拽事件
@param sender 首饰
*/
- (IBAction)panGesture:(UIPanGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateBegan) {
self.startP = [sender locationInView:self.view];
}else if (sender.state == UIGestureRecognizerStateChanged){
CGPoint currentP = [sender locationInView:self.view];
CGFloat width = currentP.x - self.startP.x;
CGFloat height = currentP.y - self.startP.y;
self.corverView.frame = CGRectMake(self.startP.x, self.startP.y, width, height);
}else if (sender.state == UIGestureRecognizerStateEnded){
// 开启图片的上下文
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
// 创建路径
UIBezierPath *path = [UIBezierPath bezierPathWithRect:self.corverView.frame];
// 超出部分进行裁剪
[path addClip];
// 拿到当前的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 开始绘制
[self.displayImageView.layer renderInContext:ctx];
// 获得图片
UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
// 关闭上下文
UIGraphicsEndImageContext();
self.displayImageView.image = getImage;
// 移除覆盖的view
[self.corverView removeFromSuperview];
}
}
- 图片擦除
- (IBAction)panGesture:(UIPanGestureRecognizer *)sender {
// 擦除的宽度
CGFloat width = 50;
CGPoint currrentP = [sender locationInView:self.view];
CGFloat pointX = currrentP.x - width *0.5;
CGFloat pointY = currrentP.y - width *0.5;
// 创建图片上下文
UIGraphicsBeginImageContextWithOptions(self.displayImageView.bounds.size, NO, 0.0);
// 获取当前的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 进行绘制
[self.displayImageView.layer renderInContext:ctx];
// 擦除区域
CGRect clearRect = CGRectMake(pointX, pointY, width, width);
// 进行擦除
CGContextClearRect(ctx, clearRect);
// 生成新的图片
UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
// 结束图片的上下文
UIGraphicsEndImageContext();
self.displayImageView.image = getImage;
- 一个手势解锁的例子(写的一般有时间在优化)
#import "GestureView.h"
#define ButtonW 70
#define ButtonLeftMargen 30
#define ButtonTopMargen 30
#define ButtonCommonMargen 10
@interface GestureView ()
@property (strong, nonatomic) NSMutableArray *buttonArray;
@property (assign, nonatomic) CGPoint currentP;
@end
@implementation GestureView
-(NSMutableArray *)buttonArray {
if (!_buttonArray) {
_buttonArray = [NSMutableArray array];
}
return _buttonArray;
}
- (void)awakeFromNib {
[super awakeFromNib];
// 创建button
for (NSInteger index = 0; index < 9; index ++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setImage:[UIImage imageNamed:@"gesture_normal"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"gesture_selected"] forState:UIControlStateSelected];
button.tag = index;
button.userInteractionEnabled = NO;
[self addSubview:button];
}
}
/**
改变一些frame
*/
- (void)layoutSubviews {
[super layoutSubviews];
// 在这里正式的设置button
for (NSInteger index = 0; index < self.subviews.count; index++) {
UIButton *button = (UIButton *)self.subviews[index];
CGFloat buttonL = (index % 3)*(ButtonW + ButtonCommonMargen);
CGFloat buttonT = (index / 3)*(ButtonW + ButtonCommonMargen);
button.frame = CGRectMake(ButtonLeftMargen + buttonL, ButtonTopMargen + buttonT, ButtonW, ButtonW);
}
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
CGPoint currentP = [self getPointWithTouchs:touches];
UIButton *button = [self getButtonThroughPoint:currentP];
if (button && button.selected == NO) {
button.selected = YES;
[self.buttonArray addObject:button];
[self setNeedsDisplay];
}
}
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
CGPoint currentP = [self getPointWithTouchs:touches];
UIButton *button = [self getButtonThroughPoint:currentP];
if (button && button.selected == NO) {
button.selected = YES;
[self.buttonArray addObject:button];
}
self.currentP = currentP;
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSString *str = [[NSString alloc] init];
for (UIButton *button in self.buttonArray) {
button.selected = NO;
str = [str stringByAppendingString:[NSString stringWithFormat:@"%zd",button.tag]];
}
NSLog(@"你想要的结果是 : %@",str);
[self.buttonArray removeAllObjects];
self.currentP = CGPointMake(0, 0);
[self setNeedsDisplay];
}
/**
通过一个点来获取button
@param point 点
@return 按钮
*/
- (UIButton *)getButtonThroughPoint:(CGPoint)point {
for (UIButton *button in self.subviews) {
if (CGRectContainsPoint(button.frame, point)) {
return button;
}
}
return nil;
}
/**
通过touches来获得当前的点
@param touches touches
@return 获取的点
*/
- (CGPoint )getPointWithTouchs:(NSSet <UITouch *> *)touches {
UITouch *touch = [touches anyObject];
return [touch locationInView:self];
}
/**
开始绘制
@param rect 矩形
*/
- (void)drawRect:(CGRect)rect {
if (self.buttonArray.count == 0) {
return;
}
UIBezierPath *path = [UIBezierPath bezierPath];
for (NSInteger index = 0; index < self.buttonArray.count; index ++) {
UIButton *button = (UIButton *)self.buttonArray[index];
if (index == 0) {
[path moveToPoint:button.center];
}else {
[path addLineToPoint:button.center];
}
}
if (self.currentP.x > 0) {
[path addLineToPoint:self.currentP];
}
[[UIColor greenColor] set];
path.lineWidth = 5;
[path setLineJoinStyle:kCGLineJoinRound];
[path stroke];
}
@end
- 涂鸦的功能
// drawView的.h 文件
#import <UIKit/UIKit.h>
@interface DrawView : UIView
/**
显示的imageview
*/
@property (nonatomic,weak)IBOutlet UIImageView *displayImageView;
/**
颜色
*/
@property (strong, nonatomic) UIColor *color;
/**
宽度
*/
@property (assign, nonatomic) CGFloat width;
/**
清除的操作
*/
- (void)clearAction;
/**
撤销的操作
*/
- (void)undoAction;
/**
橡皮擦的事件
*/
- (void)eraserAction;
@end
// drawView的.m文件
#import "DrawView.h"
#import "DrawBezierPath.h"
@interface DrawView ()
@property (strong, nonatomic) DrawBezierPath *drawPath;
@property (strong, nonatomic) NSMutableArray *pathArray;
@end
@implementation DrawView
-(NSMutableArray *)pathArray {
if (!_pathArray) {
_pathArray = [NSMutableArray array];
}
return _pathArray;
}
- (void)awakeFromNib {
[super awakeFromNib];
// 添加拖拽的事件
UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self addGestureRecognizer:panGes];
}
/**
手势拖拽的响应
@param panGesture 拖拽手势
*/
- (void)panAction:(UIPanGestureRecognizer *)panGesture{
if (panGesture.state == UIGestureRecognizerStateBegan) {
self.drawPath = [DrawBezierPath bezierPath];
CGPoint currentPoint = [panGesture locationInView:self];
[self.drawPath moveToPoint:currentPoint];
_width > 0 ? (self.drawPath.lineWidth = _width):(self.drawPath.lineWidth = 1);
_color != nil ? (self.drawPath.pathColor = _color) : (self.drawPath.pathColor = [UIColor blackColor]);
[self.pathArray addObject:self.drawPath];
}else if (panGesture.state == UIGestureRecognizerStateChanged){
CGPoint currentPoint = [panGesture locationInView:self];
[self.drawPath addLineToPoint:currentPoint];
}
[self setNeedsDisplay];
}
#pragma mark - 外部事件的响应
/**
清除的操作
*/
- (void)clearAction{
[self.pathArray removeAllObjects];
[self setNeedsDisplay];
}
/**
撤销的操作
*/
- (void)undoAction {
[self.pathArray removeLastObject];
[self setNeedsDisplay];
}
/**
橡皮擦的事件
*/
- (void)eraserAction{
self.color = self.backgroundColor;
[self setNeedsDisplay];
}
/**
设置颜色
@param color 颜色
*/
- (void)setColor:(UIColor *)color{
_color = color;
[self setNeedsDisplay];
}
/**
设置宽度
@param width 宽度
*/
- (void)setWidth:(CGFloat)width{
_width = width;
[self setNeedsDisplay];
}
/**
绘制上下文的部分
@param rect 当前的上下文的区域
*/
- (void)drawRect:(CGRect)rect {
for (DrawBezierPath *path in self.pathArray) {
[path.pathColor set];
[path stroke];
}
}
@end
// DrawBezierPath.h文件
#import <UIKit/UIKit.h>
@interface DrawBezierPath : UIBezierPath
@property (strong, nonatomic) UIColor *pathColor;
@end
// DrawBezierPath.m文件
#import "DrawBezierPath.h"
@implementation DrawBezierPath
@end
- CALayer
- layer 和view的区别:
1)view可以处理事件的响应,而layer是用来显示,不能处理事件
2)每个UIView都有一个layer提供内容的绘制与显示,并且UIView的尺寸和样式都由CALayer所提供,两者都是树形结构,layer 有一个SubLayers view有一个SubViews,但是layer比view多一个anchorPoint
3)其实个人理解view的frame都是由本身的layer的frame确定的
4)看这个链接view和layer的区别
// 阴影的透明度,默认是完全透明的也就是0
self.redView.layer.shadowOpacity = 1.0;
// 设置阴影的颜色
self.redView.layer.shadowColor = [UIColor greenColor].CGColor;
// 设置阴影的偏移量
self.redView.layer.shadowOffset = CGSizeMake(50, -50);
// 设置阴影的模糊程度
self.redView.layer.shadowRadius = 10;
- 两种方式显示图片
// 第一种方式显示图片
self.redView.layer.contents = (id)[UIImage imageNamed:@"timg"].CGImage;
self.redView.layer.cornerRadius = 50;
self.redView.layer.masksToBounds = YES;
// 第二种方式显示图片
self.displayImageView.layer.cornerRadius = 50;
self.displayImageView.layer.masksToBounds = YES;
- uiimageview也是继承view 为什么在下面的这段代码中 view就被裁剪了而imagview 没有变化 因为图片显示的是在layer的内容层上 第一个代码没有显示内容 所以可以被裁剪,如果两段代码都加上layer.masksToBounds = YES就起作用了 因为masksToBounds是裁剪根试图以及根上的所有的内容进行裁剪
// 第一种方式显示,可以裁剪
self.redView.layer.cornerRadius = 50;
// 第二种方式显示
self.displayImageView.layer.cornerRadius = 50;
- 图片3d的平移、缩放、旋转
[UIView animateWithDuration:1.0 animations:^{
// 第一种方式
// 3d的类型缩放
self.displayImageView.layer.transform = CATransform3DMakeScale(1.5, 1.8, 3.0);
// 3d类型旋转
self.displayImageView.layer.transform = CATransform3DMakeRotation(M_PI, 1.0, 1.0, 1.0);
// 3d类型旋转
self.displayImageView.layer.transform = CATransform3DMakeTranslation(100, 100, 100);
// 第二种方式
[self.displayImageView.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.8, 3.0)] forKeyPath:@"transform"];
[self.displayImageView.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 1.0, 1.0, 1.0)] forKeyPath:@"transform"];
[self.displayImageView.layer setValue:[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(100, 100, 100)] forKeyPath:@"transform"];
// 第三种方式 简单快速的实现 kvc 这种方式实现
[self.displayImageView.layer setValue:@(1.5) forKeyPath:@"transform.scale"];
[self.displayImageView.layer setValue:@(M_PI) forKeyPath:@"transform.rotation"];
[self.displayImageView.layer setValue:@(150) forKeyPath:@"transform.translation.x"];
}];
- position 和anchorPosition的区别和联系
- 解释anthorPosition 是图层的点默认在position的显示的位置,anchorPosition默认的是(0.5,0.5)范围是(0-1)表示图层的宽高比
- 这两段代码是相同的
CALayer *layer = [[CALayer alloc] init];
layer.frame = CGRectMake(0, 0, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:layer];
CALayer *layer = [[CALayer alloc] init];
layer.frame = CGRectMake(0, 0, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
layer.anchorPoint = CGPointMake(0.5, 0.5);
[self.view.layer addSublayer:layer];
- position 在0 和anchorPosition 在(0.5,0.5)
CALayer *layer = [[CALayer alloc] init];
layer.frame = CGRectMake(0, 0, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
layer.anchorPoint = CGPointMake(0.5, 0.5);
layer.position = CGPointMake(0, 0);
[self.view.layer addSublayer:layer];
- position 在(30,50) 和anchorPosition 在(0,0)
CALayer *layer = [[CALayer alloc] init];
layer.frame = CGRectMake(0, 0, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
layer.anchorPoint = CGPointMake(0, 0);
layer.position = CGPointMake(30,50);
[self.view.layer addSublayer:layer];
- 隐式动画
- 自己的理解:他是系统非根层的动画,有我们自己创建的layer像改变position 、bounds、还有backgroundColor 等等的会存在默认的动画,原因是系统会创建一个包装的对象对他们进行包装,包装完毕才会执行改变
- (void)viewDidLoad {
[super viewDidLoad];
CALayer *layer = [[CALayer alloc] init];
layer.frame = CGRectMake(0, 0, 100, 100);
layer.backgroundColor = [UIColor redColor].CGColor;
layer.anchorPoint = CGPointMake(0, 0);
layer.position = CGPointMake(30,50);
self.layer = layer;
[self.view.layer addSublayer:layer];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[CATransaction begin];
// 取消动画
[CATransaction setDisableActions:YES];
// 设置动画的时常
[CATransaction setAnimationDuration:5.0];
self.layer.backgroundColor = [UIColor greenColor].CGColor;
self.layer.position = CGPointMake(100, 200);
[CATransaction commit];
}
- 心跳动画 主要是CABasicAnimation的使用
- 一些属性的说明(他的主要作用是 平移、旋转、缩放这些)
duration 动画的时间
repeatCount 重复的次数。不停重复设置为 HUGE_VALF
repeatDuration 设置动画的时间。
beginTime 指定动画开始的时间。从开始延迟几秒的话,设置为【CACurrentMediaTime() + 秒数】 的方式
timingFunction 设置动画的速度变化
autoreverses 动画结束时是否执行逆动画
fromValue 所改变属性的起始值
toValue 所改变属性的结束时的值
byValue 所改变属性相同起始值的改变量 - 心跳动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.duration = 1.5;
animation.fromValue = @(0);
animation.toValue = @(2);
// 无限重复
animation.repeatCount = NSIntegerMax;
// 自动恢复原来的位置(有一个恢复的动画)
animation.autoreverses = YES;
// 确定完成后动画是否从目标图层的动画中移除。
// 当“是”时,一旦活动持续时间过去,动画将从目标图层的动画中移除。 默认为YES
animation.removedOnCompletion = NO;
[self.heartimageView.layer addAnimation:animation forKey:nil];
- 移动的动画
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.duration = 2;
animation.repeatCount = NSIntegerMax;
animation.beginTime =CACurrentMediaTime() + 1;// 1秒后执行
animation.fromValue = [NSValue valueWithCGPoint:self.heartimageView.layer.position]; // 起始帧
animation.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 300)]; // 终了帧
// 视图添加动画
[self.heartimageView.layer addAnimation:animation forKey:@"move-layer"];
- 旋转的动画
// 对Y轴进行旋转(指定Z轴的话,就和UIView的动画一样绕中心旋转)
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
animation.duration = 2;
animation.repeatCount = NSIntegerMax;
animation.beginTime = CACurrentMediaTime() + 1; // 1秒后执行
animation.fromValue = [NSNumber numberWithFloat:0.0]; // 起始角度
// 动画结束后停在最后位置状态的解决方法
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
animation.toValue = [NSNumber numberWithFloat:M_PI]; // 终止角度
[self.heartimageView.layer addAnimation:animation forKey:@"rotate-layer"];
- 透明度的动画
//opacity 指layer的透明度
CABasicAnimation *basicAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
basicAnimation.fromValue = @(1.0);
basicAnimation.toValue = @(0.0);//[NSNumber numberWithFloat:0.0]
basicAnimation.duration = 1.5;
[self.heartimageView.layer addAnimation:basicAnimation forKey:@"op"];
- CAKeyframeAnimation 这个是线性的动画
- 实现 一个图片绕着圆旋转
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 100, 100)];
animation.path = path.CGPath;
animation.duration = 3.0;
animation.repeatCount = NSIntegerMax;
// 自动恢复原位
animation.autoreverses = YES;
// 动画结束后停在最后位置状态的解决方法
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
// 线性起搏,可使动画在其持续时间内均匀发生
// kCAMediaTimingFunctionEaseInEaseOut: 轻松放松起搏,可以使动画开始缓慢,在其持续时间的中间加速,然后在完成之前再次放慢速度。
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.heartimageView.layer addAnimation:animation forKey:nil];
- 图片的抖动
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
animation.values = @[@(angele(-10)),@(angele(0))];
animation.duration = 1.0;
animation.repeatCount = NSIntegerMax;
// 自动恢复原位
animation.autoreverses = YES;
// 动画结束后停在最后位置状态的解决方法
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
// 线性起搏,可使动画在其持续时间内均匀发生
// kCAMediaTimingFunctionEaseInEaseOut: 轻松放松起搏,可以使动画开始缓慢,在其持续时间的中间加速,然后在完成之前再次放慢速度。
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.heartimageView.layer addAnimation:animation forKey:nil];
- 转场动画 (CATransition)
- 图片的翻页效果
index_ ++;
if (index_ > 3 ) {
index_ = 1;
}
NSString *imageName = [NSString stringWithFormat:@"%d",index_];
self.heartimageView.image = [UIImage imageNamed:imageName];
CATransition *animation = [CATransition animation];
/*
type:动画过渡类型
subtype:动画过渡方向
startProgress:动画起点(在整体动画的百分比)
endProgress:动画终点(在整体动画的百分比)
*/
// 动画的过度类型
// animation.type = kCATransitionMoveIn;
// 或者这个方式也行
/*
关于type的总结 后面的一张图片
*/
animation.type = @"pageCurl";
// 动画的过度方向
animation.subtype = kCATransitionFromRight;
animation.startProgress = 0.1;
animation.endProgress = 0.7;
[self.heartimageView.layer addAnimation:animation forKey:nil];
-
关于type的总结
- CATransition的另外一种使用
自带的动画
[UIView transitionWithView:self.heartimageView duration:2.0 options:UIViewAnimationOptionTransitionFlipFromBottom animations:^{
index_ ++;
if (index_ > 3 ) {
index_ = 1;
}
NSString *imageName = [NSString stringWithFormat:@"%d",index_];
self.heartimageView.image = [UIImage imageNamed:imageName];
} completion:nil];
- 自带动画2
// 前台页面
UIView *frontView = [[UIView alloc] initWithFrame:self.view.bounds];
frontView.backgroundColor = [UIColor colorWithRed:0.345 green:0.349 blue:0.365 alpha:1.000];
UIImageView *caLogoView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"1"]];
caLogoView.frame = CGRectMake(70, 80, caLogoView.bounds.size.width, caLogoView.bounds.size.height);
[frontView addSubview:caLogoView];
self.frontView = frontView;
// 后台页面
UIImage *backImage = [UIImage imageNamed:@"2"];
UIImageView *backView = [[UIImageView alloc] initWithImage:backImage];
backView.userInteractionEnabled = YES;
self.backView = backView;
[self.view addSubview:backView];
[self.view addSubview:frontView];
// formcview :在执行动画的过程中,他将会从superview 删除
// toView :执行动画结束添加到fromview的父视图
[UIView transitionFromView:self.frontView // 从原来视图转到新视图的动画效果设置
toView:self.backView duration:1.0f
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:nil];
- 动画组
CAAnimationGroup *group = [CAAnimationGroup animation];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
animation.fromValue = @(0);
animation.toValue = @(1.5);
CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.fromValue = @(0);
rotationAnimation.toValue = @(M_PI);
group.animations = @[animation,rotationAnimation];
group.duration = 1.5;
group.repeatCount = NSIntegerMax;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
[self.heartimageView.layer addAnimation:group forKey:nil];
- UIView的动画和图层动画的区别是:
1.涂层动画不能处理点击等等的事件,本身的frame并不改变。
2.UIView的动画可以出点点击事件等等 完成与用户的交互。 - 一个图片折叠的动画
-(void)viewDidLoad {
[super viewDidLoad];
self.heartimageView.layer.contentsRect = CGRectMake(0, 0, 1, 0.5);
self.bottomImageView.layer.contentsRect = CGRectMake(0, 0.5, 1, 0.5);
self.heartimageView.layer.anchorPoint = CGPointMake(0.5, 1);
self.bottomImageView.layer.anchorPoint = CGPointMake(0.5, 0);
// 添加拖拽的手势
UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self.view addGestureRecognizer:panGes];
// 添加隐影的操作(梯度的layer )
CAGradientLayer *grandientLayer = [CAGradientLayer layer];
grandientLayer.frame = self.bottomImageView.bounds;
grandientLayer.colors = @[(id)[UIColor blackColor].CGColor,(id)[UIColor clearColor].CGColor];
// 确定颜色的渐变方向
grandientLayer.startPoint = CGPointMake(0, 0);
grandientLayer.endPoint = CGPointMake(1.0, 1.0);
// 一个颜色到下一个颜色开始渐变的位置
grandientLayer.locations = @[@(0.2),@(0.8)];
// 暗影
grandientLayer.shadowOpacity = 0.0;
// 不透明度
grandientLayer.opacity = 0.0;
self.grandientLayer = grandientLayer;
[self.bottomImageView.layer addSublayer:grandientLayer];
}
/**
添加拖拽的手势
@param panGes 手势的点击
*/
- (void)panAction:(UIPanGestureRecognizer *)panGes {
CGPoint point = [panGes locationInView:self.view];
CGFloat angle = M_PI * 1.0 * point.y /self.view.bounds.size.height;
CATransform3D transform = CATransform3DIdentity;
// 立体效果 离你眼睛越近 看的越清楚 离你眼睛越远 看的越小
transform.m34 = -1.0/500.0;
self.heartimageView.layer.transform = CATransform3DRotate(transform, -angle, 1.0, 0, 0);
// 改变透明度
self.grandientLayer.opacity = 1.0 * point.y /self.view.bounds.size.height;
// 结束了进行反弹回去
if (panGes.state == UIGestureRecognizerStateEnded) {
// 一个动画
// delay:动画开始时的等待时间,默认为0
// usingSpringWithDamping: 反弹系数
// initialSpringVelocity:动画的速度
[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
// 去掉所有的动画 回去
self.heartimageView.layer.transform = CATransform3DIdentity;
self.grandientLayer.opacity = 0.0;
} completion:nil];
}
}
- 音乐震动条(类似于网易云音乐)
音乐震动条 - 利用 制作到影的动画
CAReplicatorLayer *replicatorLayer = (CAReplicatorLayer *)self.view.layer;
replicatorLayer.instanceCount = 2;
//CAReplicatorLayer 旋转是按照本身的锚点来进行旋转的(这里是屏幕的正中央)
replicatorLayer.instanceTransform = CATransform3DMakeRotation(M_PI, 1, 0, 0);
// 绘制阴影
replicatorLayer.instanceRedOffset -= 0.1;
replicatorLayer.instanceBlueOffset -= 0.1;
replicatorLayer.instanceGreenOffset -= 0.1;
// 透明度
replicatorLayer.instanceAlphaOffset -= 0.1;
- 一个根据线条变化的动画
DrewView.h文件
/**
开始的事件
*/
- (void)startAction;
/**
重绘的方法
*/
- (void)redrewAction;
DrewView.m 文件
//
// DrewView.m
// 基本动画的练习
//
// Created by apple on 2018/3/19.
// Copyright © 2018年 apple. All rights reserved.
//
#import "DrewView.h"
@interface DrewView ()
@property (strong, nonatomic) UIBezierPath *path;
@property (strong, nonatomic) CALayer *myLayer;
@property (strong, nonatomic) CAReplicatorLayer *replicatorLayer;
@end
@implementation DrewView
-(void)awakeFromNib {
[super awakeFromNib];
// 创建一个path
UIBezierPath *path = [UIBezierPath bezierPath];
self.path = path;
// 创建手势
UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self addGestureRecognizer:panGes];
// 创建一个layer
CALayer *myLayer = [[CALayer alloc] init];
myLayer.frame = CGRectMake(-10, 0, 10, 10);
myLayer.cornerRadius = 5;
myLayer.backgroundColor = [UIColor redColor].CGColor;
self.myLayer = myLayer;
// 创建复制层
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
replicatorLayer.instanceDelay = 0.25;
[replicatorLayer addSublayer:self.myLayer];
[self.layer addSublayer:replicatorLayer];
self.replicatorLayer = replicatorLayer;
}
/**
拖拽的手势
@param panGes 手势
*/
- (void)panAction:(UIPanGestureRecognizer *)panGes{
CGPoint currentPoint = [panGes locationInView:self];
if (panGes.state == UIGestureRecognizerStateBegan) {
[self.path moveToPoint:currentPoint];
}else if (panGes.state == UIGestureRecognizerStateChanged){
[self.path addLineToPoint:currentPoint];
[self setNeedsDisplay];
}else if (panGes.state == UIGestureRecognizerStateEnded){
[self setNeedsDisplay];
}
}
/**
开始绘制
@param rect rect
*/
-(void)drawRect:(CGRect)rect {
[self.path stroke];
}
/**
开始的事件
*/
- (void)startAction{
// 创建动画
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
animation.path = self.path.CGPath;
animation.duration = 1.0;
animation.repeatCount = NSIntegerMax;
// 自动复位
animation.autoreverses = YES;
// 消除停在最后的位置
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
// 动画匀速
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.myLayer addAnimation:animation forKey:nil];
// 复制层
self.replicatorLayer.instanceCount = 30;
// self.replicatorLayer.instanceTransform = CATransform3DMakeTranslation(0, 2, 0);
}
/**
重绘的方法
*/
- (void)redrewAction{
[self.path removeAllPoints];
[self.myLayer removeAllAnimations];
[self setNeedsDisplay];
}
@end
- qq 粘性动画
bagdeButton.h文件
#import <UIKit/UIKit.h>
@interface bagdeButton : UIButton
@end
bagdeButton.m文件
#import "bagdeButton.h"
@interface bagdeButton ()
@property (strong, nonatomic) UIView *smallView;
@property (strong, nonatomic) CAShapeLayer *shapeLayer;
@end
@implementation bagdeButton
-(CAShapeLayer *)shapeLayer {
if (!_shapeLayer) {
// 创建根据路线显示涂层的层(形状图层)
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.fillColor = [UIColor redColor].CGColor;
[self.superview.layer insertSublayer:shapeLayer atIndex:0];
_shapeLayer = shapeLayer;
}
return _shapeLayer;
}
-(void)awakeFromNib {
[super awakeFromNib];
// 初始化
[self setUp];
}
-(instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// 初始化
[self setUp];
}
return self;
}
/**
初始化
*/
- (void)setUp{
// 本身的基本的设置
self.layer.cornerRadius = self.bounds.size.width *0.5;
self.layer.masksToBounds = YES;
self.titleLabel.textColor = [UIColor whiteColor];
self.backgroundColor = [UIColor redColor];
self.titleLabel.font = [UIFont systemFontOfSize:12.0];
// 添加拖拽的手势
UIPanGestureRecognizer *panGes = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self addGestureRecognizer:panGes];
// 添加小圆
UIView *smallView = [[UIView alloc] initWithFrame:self.frame];
smallView.backgroundColor = [UIColor redColor];
smallView.layer.cornerRadius = self.bounds.size.width *0.5;
self.smallView = smallView;
[self.superview insertSubview:smallView belowSubview:self];
}
/**
拖拽的手势
@param panGes 手势
*/
- (void)panAction:(UIPanGestureRecognizer *)panGes {
// 当前weiz的偏移量
CGPoint panOff = [panGes locationInView:self.superview];
CGRect frame = self.frame;
frame.origin = panOff;
self.frame = frame;
// 计算两个圆直接的距离
CGFloat dx1 = self.frame.origin.x - self.smallView.frame.origin.x;
CGFloat dy1 = self.frame.origin.y - self.smallView.frame.origin.y;
// 相当于求三角形的斜边
CGFloat d = hypotf(dx1, dy1);
// 改变小圆的frame
CGRect smallRect = self.smallView.frame;
CGFloat calculatorWidth = self.frame.size.width - self.frame.size.width *(1.0 * d/60);
if (calculatorWidth <= 0) {
calculatorWidth = 0;
}
smallRect.size.width = calculatorWidth;
smallRect.size.height = calculatorWidth;
self.smallView.frame = smallRect;
self.smallView.layer.cornerRadius = calculatorWidth * 0.5;
UIBezierPath *path = [self pathWithSmallView:self.smallView andBigView:self andRadius:d];
self.shapeLayer.path = path.CGPath;
if (panGes.state == UIGestureRecognizerStateEnded) {
if (d < 60) {
CGRect frame = self.frame;
frame.origin = self.smallView.frame.origin;
self.frame = frame;
[self.shapeLayer removeFromSuperlayer];
self.smallView.frame = self.frame;
self.smallView.layer.cornerRadius = self.frame.size.width * 0.5;
self.smallView.hidden = NO;
}else {
[self.shapeLayer removeFromSuperlayer];
self.smallView.hidden = YES;
// 创建一个imageview 来进行一个爆炸的效果
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.origin.x, self.frame.origin.y, 100, 100)];
NSMutableArray *imagesArray = [NSMutableArray array];
for (NSInteger index = 1; index < 4; index ++) {
NSString *imageName = [NSString stringWithFormat:@"%zd",index];
UIImage *image = [UIImage imageNamed:imageName];
[imagesArray addObject:image];
}
imageView.animationImages = imagesArray;
[imageView startAnimating];
[self.superview addSubview:imageView];
// 移动从父试图
[self removeFromSuperview];
}
}
}
/**
根据小圆和大圆返回路径
@param smallView 小圆
@param bigButton 大圆
@param d 半径
@return 路径
*/
- (UIBezierPath *)pathWithSmallView:(UIView *)smallView andBigView:(UIButton *)bigButton andRadius:(CGFloat )d{
// 求各个点的值
CGFloat x1 = smallView.center.x;
CGFloat y1 = smallView.center.y;
CGFloat x2 = bigButton.center.x;
CGFloat y2 = bigButton.center.y;
CGFloat r1 = smallView.frame.size.width * 0.5;
CGFloat r2 = bigButton.frame.size.width * 0.5;
CGFloat siny = (x2 - x1)/d;
CGFloat cosy = (y1 - y2)/d;
CGPoint A = CGPointMake(x1 - cosy*r1, y1 - siny*r1);
CGPoint B = CGPointMake(x1 + cosy*r1, y1 + siny*r1);
CGPoint C = CGPointMake(x2 - cosy*r2, y2 - siny*r2);
CGPoint D = CGPointMake(x2 + cosy*r2, y2 + siny*r2);
CGPoint P = CGPointMake(A.x + siny*d/2.0, A.y - cosy*d/2.0);
CGPoint O = CGPointMake(B.x + siny*d/2.0, B.y - cosy*d/2.0);
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:A];
// 曲线
[path addQuadCurveToPoint:C controlPoint:P];
[path addLineToPoint:D];
// 曲线
[path addQuadCurveToPoint:B controlPoint:O];
[path addLineToPoint:A];
return path;
}
- 微博的动画(类似与点击微博的➕)
WeiBoViewController.h文件
#import <UIKit/UIKit.h>
@interface WeiBoViewController : UIViewController
@end
WeiBoViewController.m文件
#import "WeiBoViewController.h"
@interface WeiBoViewController ()
@property (strong, nonatomic) NSMutableArray *buttonArray;
@property (strong, nonatomic) NSTimer *timer;
@property (assign, nonatomic) int index;
@end
@implementation WeiBoViewController
-(NSMutableArray *)buttonArray {
if (!_buttonArray) {
_buttonArray = [NSMutableArray array];
}
return _buttonArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 初始化
[self setUp];
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerChange) userInfo:nil repeats:YES];
}
/**
定时器改变的方法
*/
- (void)timerChange{
if (self.index == self.buttonArray.count) {
[self.timer invalidate];
self.timer = nil;
return;
}
UIButton *button = self.buttonArray[self.index];
// 这个动画有弹性效果
[UIView animateWithDuration:0.2 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
// 恢复开始的样子
button.transform = CGAffineTransformIdentity;
} completion:nil];
self.index ++;
}
/**
初始化
*/
- (void)setUp{
int row = 0;
int column = 0;
for (NSInteger index = 0; index < 6; index++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
row = (int)index/3;
column = (int)index%3;
button.backgroundColor = [UIColor redColor];
button.frame = CGRectMake(10 + column*(80 + 20), 467 + row*(80+20), 80, 80);
[button setTitle:@"微博"forState:UIControlStateNormal];
[self.view addSubview:button];
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchDown];
[button addTarget:self action:@selector(buttonClickUpInside:) forControlEvents:UIControlEventTouchUpInside];
// 移动到最底部
button.transform = CGAffineTransformMakeTranslation(button.frame.origin.x, self.view.bounds.size.height);
[self.buttonArray addObject:button];
}
}
/**
按钮按下事件
@param button 按钮
*/
- (void)buttonClick:(UIButton *)button{
button.transform = CGAffineTransformMakeScale(1.2, 1.2);
}
/**
按钮按下抬起
@param button 按钮
*/
- (void)buttonClickUpInside:(UIButton *)button {
[UIView animateWithDuration:1.0 animations:^{
button.transform = CGAffineTransformMakeScale(2, 2);
}completion:^(BOOL finished) {
button.alpha = 0;
}];
}
@end
- 例子效果
// 创建粒子效果的layer
CAEmitterLayer *emiterLayer = [[CAEmitterLayer alloc] init];
// 创建发射器的位置
emiterLayer.position = CGPointMake(self.view.bounds.size.width * 0.5, 100);
// 开启三维的效果
emiterLayer.preservesDepth = YES;
// 创建每一个cell 并且给每一个cell添加属性
CAEmitterCell *cell = [[CAEmitterCell alloc] init];
// 设置粒子的速度
cell.velocity = 100;
cell.velocityRange = 50;
// 例子的大小 scaleRange:(相当于scale 是 1.2 - 0.2)
cell.scale = 0.7;
cell.scaleRange = 0.5;
// 粒子的方向
cell.emissionLongitude = M_PI_2;
cell.emissionRange = 0.5 * M_PI_2;
// 设置每一秒弹出多少个
cell.birthRate = 10;
// 设置例子的旋转
cell.spin = M_PI_2;
cell.spinRange = M_PI_2;
// 例子的存活时间
cell.lifetime = 5;
cell.lifetimeRange = 3;
// 设置粒子的图片
cell.contents = (id)[UIImage imageNamed:@"good6_30x30_"].CGImage;
emiterLayer.emitterCells = @[cell];
[self.view.layer addSublayer:emiterLayer];
- 补充 CAShapeLayer
- 作用 :根据路径显示图形
链接 - 终于总结完了 花了我两个星期的时间,如果大家感觉有什么不对的,千万给予指正,我将不胜荣幸!