当前位置: 移动技术网 > 移动技术>移动开发>IOS > iOS粒子路径移动效果 iOS实现QQ拖动效果

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

2019年07月24日  | 移动技术网移动技术  | 我要评论

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

一、图示

这里写图片描述

二、分析

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

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

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

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

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

//获取两个圆之间的距离
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)——它可以根据一个路径生成一个形状。

路径分析如下图

根据上面我们需要创建一个 abcda 其中da和bc是曲线,控制点分别为o和p。

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

三、代码

2.1 bagevalueview.m

//
// 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

//
// 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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网