iOS粒子路径移动效果 iOS实现QQ拖动效果

时间:2021-12-09 07:11:31

粒子效果,QQ拖动效果,实现很简单,具体代码如下

一、图示

iOS粒子路径移动效果 iOS实现QQ拖动效果

二、分析

我们要实现的如果如上面的图示,那么我们可以按照下面的步骤操作:

第一步:我们的红点其实是一个UIButton。创建一个BageValueView继承自UIButton

第二步:初始化的时候,初始化控件,设置圆角,修改背景、文字颜色

第三步:添加手势。在手势的处理中我们,我们需要让当前控件随着手指移动而移动。

第四步:控件一开始创建的时候,其实有两个圆,一个就是我们能够拖动的大圆,另外一个就是原始位置上会改变大小的圆。这一步骤中,主要就是创建这个小圆,它的初始参数和大圆一样。
在手势的处理中,根据两圆的位置,来计算小圆半径,当两圆的位置大于最大位置时候,小圆隐藏掉。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//获取两个圆之间的距离
CGFloat distance = [self distanceWithSmallCircle:self.smallCircle bigCircle:self];
if(distance<=MAX_DIST){//只有距离不超过最大距离才计算小圆半径
 //计算小圆的半径
 //小圆半径最小的时候是MIN_RADIUS,这个时候两个圆达到最大距离MAX_DIST
 //小圆半径最大的时候是原始半径,这个时候两圆距离是0
 //处于前面两者之间的时候,小圆的半径是:MIN_RADIUS + (原始半径 - MIN_RADIUS)/MAX_DIST * (MAX_DIST - 当前的距离)
 CGFloat smallR = self.bounds.size.width * 0.5;
 smallR = MIN_RADIUS + (MAX_DIST-distance) * (smallR-MIN_RADIUS)/MAX_DIST;
 //重新设置小圆的尺寸
 self.smallCircle.bounds = CGRectMake(0, 0, smallR*2, smallR*2);
 //重新设置小圆的半径
 self.smallCircle.layer.cornerRadius = smallR;
}else{//超过了最大距离
 self.smallCircle.hidden = YES;
}

第五步:创建大小圆之间的连接部分。连接部分我们需要创建一个形状图层(CAShapeLayer)——它可以根据一个路径生成一个形状。

路径分析如下图

iOS粒子路径移动效果 iOS实现QQ拖动效果

根据上面我们需要创建一个 ABCDA 其中DA和BC是曲线,控制点分别为O和P。

第六步:当手势结束的时候,我们需要判断当前两圆的位置,如果小圆最大距离,那么复位。如果大于最大距离,那么添加一个销毁动画。

三、代码

2.1 BageValueView.m

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
//
// BageValueView.m
// 03_UIView78_粒子效果2
//
// Created by 杞文明 on 17/7/22.
// Copyright © 2017年 杞文明. All rights reserved.
//
 
#import "BageValueView.h"
 
#define MAX_DIST 80
#define MIN_RADIUS 5
@interface BageValueView()
 
@property (nonatomic, weak) UIView *smallCircle;
@property (nonatomic, weak) CAShapeLayer *shap;
 
 
@end
 
@implementation BageValueView
 
-(void)awakeFromNib{
 [self setUp];
}
 
-(instancetype)initWithFrame:(CGRect)frame{
 if ( self = [super initWithFrame:frame] ) {
  [self setUp];
 }
 return self;
}
 
//形状图层
-(CAShapeLayer*)shap{
 if(_shap == nil){
  //形状图层,它可以根据一个路径生成一个形状
  CAShapeLayer *shap = [CAShapeLayer layer];
  //设置形状填充色
  shap.fillColor = [UIColor redColor].CGColor;
  _shap = shap;
  //添加到最底层
  [self.superview.layer insertSublayer:shap atIndex:0];
 }
 return _shap;
}
 
//初始化
-(void)setUp{
 //设置圆角
 self.layer.cornerRadius = self.bounds.size.width * 0.5;
 
 //设置背景文字颜色
 [self setBackgroundColor:[UIColor redColor]];
 [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
 self.titleLabel.font = [UIFont systemFontOfSize:12];
 
 //添加手势
 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
 [self addGestureRecognizer:pan];
 
 //添加小圆
 UIView *smallCircle = [[UIView alloc]initWithFrame:self.frame];
 smallCircle.backgroundColor = self.backgroundColor;
 smallCircle.layer.cornerRadius = self.layer.cornerRadius;
 self.smallCircle = smallCircle;
 //把小圆添加到父控件中,并且在大圆下面
 [self.superview insertSubview:smallCircle belowSubview:self];
 
}
 
-(void)pan:(UIPanGestureRecognizer*)pan{
 //获取当前点
 CGPoint currentP = [pan translationInView:self];
 //移动
 CGPoint center = self.center;
 center.x += currentP.x;
 center.y += currentP.y;
 self.center = center;
 //复位
 [pan setTranslation:CGPointZero inView:self];
 
 //获取两个圆之间的距离
 CGFloat distance = [self distanceWithSmallCircle:self.smallCircle bigCircle:self];
 if(distance<=MAX_DIST){//只有距离不超过最大距离才计算小圆半径
  //计算小圆的半径
  //小圆半径最小的时候是MIN_RADIUS,这个时候两个圆达到最大距离MAX_DIST
  //小圆半径最大的时候是原始半径,这个时候两圆距离是0
  //处于前面两者之间的时候,小圆的半径是:MIN_RADIUS + (原始半径 - MIN_RADIUS)/MAX_DIST * (MAX_DIST - 当前的距离)
  CGFloat smallR = self.bounds.size.width * 0.5;
  smallR = MIN_RADIUS + (MAX_DIST-distance) * (smallR-MIN_RADIUS)/MAX_DIST;
  //重新设置小圆的尺寸
  self.smallCircle.bounds = CGRectMake(0, 0, smallR*2, smallR*2);
  //重新设置小圆的半径
  self.smallCircle.layer.cornerRadius = smallR;
 }else{//超过了最大距离
  self.smallCircle.hidden = YES;
  [self.shap removeFromSuperlayer];
 }
 
 //创建不规则路径,其实就是连个圆之间连接的部分
 //小圆不隐藏才创建
 if(self.smallCircle.hidden == NO){
  UIBezierPath *path = [self pathWithSmallCircle:self.smallCircle bigCircle:self];
  self.shap.path = path.CGPath;
 }
 
 //当手指松开的时候
 if (pan.state==UIGestureRecognizerStateEnded) {
  //如果两圆之间的距离小于最大距离,大圆复位
  if (distance<MAX_DIST) {
   //移除形状图层
   [self.shap removeFromSuperlayer];
   //添加一个弹性动画
   [UIView animateWithDuration:0.25 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:0 options:UIViewAnimationOptionCurveLinear animations:^{
    //大圆复位
    self.center = self.smallCircle.center;
   } completion:^(BOOL finished) {
    //小圆显示
    self.smallCircle.hidden = NO;
   }];
  } else {
   //距离大于最大位置的时候,播放动画,按钮从父控件中删除
   //添加一个UIImageView 用来播放动画
   UIImageView *imageV = [[UIImageView alloc] initWithFrame:self.bounds];
   [self addSubview:imageV];
 
   //添加图片
   NSMutableArray *imageArray = [NSMutableArray array];
   for (int i=1; i<=8; i++) {
    NSString *imageName = [NSString stringWithFormat:@"%d",i];
    UIImage *image = [UIImage imageNamed:imageName];
    [imageArray addObject:image];
   }
   imageV.animationImages = imageArray;
   //设置动画时长
   [imageV setAnimationDuration:1];
   //开始动画
   [imageV startAnimating];
 
   //一秒钟后.把当前的按钮从父控件当中移.
   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self removeFromSuperview];
   });
  }
 }
}
 
//计算两个圆之间的距离 使用勾股定理:两直角边的平方和等于斜边的平方
- (CGFloat)distanceWithSmallCircle:(UIView *)smallCircle bigCircle:(UIView *)bigCircle{
 //X轴上的偏移量(就是x1-x2的值)
 CGFloat offsetX = bigCircle.center.x - smallCircle.center.x;
 //y轴上的偏移量(就是y1-y2的值)
 CGFloat offsetY = bigCircle.center.y - smallCircle.center.y;
 
 return sqrt(offsetX*offsetX + offsetY*offsetY);
}
 
//根据两个圆设置一个不规的路径
- (UIBezierPath *)pathWithSmallCircle:(UIView *)smallCircle bigCircle:(UIView *)bigCircle{
 
 CGFloat x1 = smallCircle.center.x;
 CGFloat y1 = smallCircle.center.y;
 
 CGFloat x2 = bigCircle.center.x;
 CGFloat y2 = bigCircle.center.y;
 
 CGFloat d = [self distanceWithSmallCircle:smallCircle bigCircle:self];
 
 if (d <= 0) {
  return nil;
 }
 
 
 CGFloat cosθ = (y2 - y1) / d;
 CGFloat sinθ = (x2 - x1) / d;
 
 CGFloat r1 = smallCircle.bounds.size.width * 0.5;
 CGFloat r2 = bigCircle.bounds.size.width * 0.5;
 
 CGPoint pointA = CGPointMake(x1 - r1 * cosθ, y1 + r1 * sinθ);
 CGPoint pointB = CGPointMake(x1 + r1 * cosθ, y1 - r1 * sinθ);
 CGPoint pointC = CGPointMake(x2 + r2 * cosθ, y2 - r2 * sinθ);
 CGPoint pointD = CGPointMake(x2 - r2 * cosθ, y2 + r2 * sinθ);
 CGPoint pointO = CGPointMake(pointA.x + d * 0.5 * sinθ, pointA.y + d * 0.5 * cosθ);
 CGPoint pointP = CGPointMake(pointB.x + d * 0.5 * sinθ, pointB.y + d * 0.5 * cosθ);
 
 
 UIBezierPath *path = [UIBezierPath bezierPath];
 //AB
 [path moveToPoint:pointA];
 [path addLineToPoint:pointB];
 //BC(曲线)
 [path addQuadCurveToPoint:pointC controlPoint:pointP];
 //CD
 [path addLineToPoint:pointD];
 //DA(曲线)
 [path addQuadCurveToPoint:pointA controlPoint:pointO];
 
 return path;
 
}
 
 
//清空高亮状态
-(void)setHighlighted:(BOOL)highlighted{}
 
@end

2.2 ViewController.m

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//
// ViewController.m
// 03_UIView78_粒子效果2
//
// Created by 杞文明 on 17/7/22.
// Copyright © 2017年 杞文明. All rights reserved.
//
 
#import "ViewController.h"
 
@interface ViewController ()
 
@end
 
@implementation ViewController
 
- (void)viewDidLoad {
 [super viewDidLoad];
 //让View在显示时不要把Autoresizing转成自动布局
 self.view.translatesAutoresizingMaskIntoConstraints = NO;
}
 
 
@end

 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。