iOS粒子路徑移動效果 iOS實現(xiàn)QQ拖動效果
粒子效果,QQ拖動效果,實現(xiàn)很簡單,具體代碼如下
一、圖示

二、分析
我們要實現(xiàn)的如果如上面的圖示,那么我們可以按照下面的步驟操作:
第一步:我們的紅點其實是一個UIButton。創(chuàng)建一個BageValueView繼承自UIButton
第二步:初始化的時候,初始化控件,設(shè)置圓角,修改背景、文字顏色
第三步:添加手勢。在手勢的處理中我們,我們需要讓當前控件隨著手指移動而移動。
第四步:控件一開始創(chuàng)建的時候,其實有兩個圓,一個就是我們能夠拖動的大圓,另外一個就是原始位置上會改變大小的圓。這一步驟中,主要就是創(chuàng)建這個小圓,它的初始參數(shù)和大圓一樣。
在手勢的處理中,根據(jù)兩圓的位置,來計算小圓半徑,當兩圓的位置大于最大位置時候,小圓隱藏掉。
//獲取兩個圓之間的距離
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;
//重新設(shè)置小圓的尺寸
self.smallCircle.bounds = CGRectMake(0, 0, smallR*2, smallR*2);
//重新設(shè)置小圓的半徑
self.smallCircle.layer.cornerRadius = smallR;
}else{//超過了最大距離
self.smallCircle.hidden = YES;
}
第五步:創(chuàng)建大小圓之間的連接部分。連接部分我們需要創(chuàng)建一個形狀圖層(CAShapeLayer)——它可以根據(jù)一個路徑生成一個形狀。
路徑分析如下圖

根據(jù)上面我們需要創(chuàng)建一個 ABCDA 其中DA和BC是曲線,控制點分別為O和P。
第六步:當手勢結(jié)束的時候,我們需要判斷當前兩圓的位置,如果小圓最大距離,那么復位。如果大于最大距離,那么添加一個銷毀動畫。
三、代碼
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){
//形狀圖層,它可以根據(jù)一個路徑生成一個形狀
CAShapeLayer *shap = [CAShapeLayer layer];
//設(shè)置形狀填充色
shap.fillColor = [UIColor redColor].CGColor;
_shap = shap;
//添加到最底層
[self.superview.layer insertSublayer:shap atIndex:0];
}
return _shap;
}
//初始化
-(void)setUp{
//設(shè)置圓角
self.layer.cornerRadius = self.bounds.size.width * 0.5;
//設(shè)置背景文字顏色
[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;
//重新設(shè)置小圓的尺寸
self.smallCircle.bounds = CGRectMake(0, 0, smallR*2, smallR*2);
//重新設(shè)置小圓的半徑
self.smallCircle.layer.cornerRadius = smallR;
}else{//超過了最大距離
self.smallCircle.hidden = YES;
[self.shap removeFromSuperlayer];
}
//創(chuàng)建不規(guī)則路徑,其實就是連個圓之間連接的部分
//小圓不隱藏才創(chuàng)建
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;
//設(shè)置動畫時長
[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);
}
//根據(jù)兩個圓設(shè)置一個不規(guī)的路徑
- (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;
}
//清空高亮狀態(tài)
-(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轉(zhuǎn)成自動布局
self.view.translatesAutoresizingMaskIntoConstraints = NO;
}
@end
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
iOS的UIColor類與其相關(guān)類之間的區(qū)別及判斷相等的方法
這篇文章主要介紹了iOS的UIColor類與其相關(guān)類之間的區(qū)別及判斷相等的方法,主要是對比了CGColor和CIColor,需要的朋友可以參考下2015-10-10
iOS App中UILabel的自定義及在Auto Layout中的使用
這篇文章主要介紹了iOS App中UILabel的自定義及在Auto Layout中的使用,示例代碼為傳統(tǒng)的Objective-C語言,需要的朋友可以參考下2016-03-03
iOS開發(fā)中使app獲取本機通訊錄的實現(xiàn)代碼實例
這篇文章主要介紹了iOS開發(fā)中使app獲取本機通訊錄的實現(xiàn)代碼實例,主要用到了AddressBook.framework和AddressBookUI.framework,代碼基于傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-01-01
iOS Swift 值類型與引用類型使用區(qū)別基礎(chǔ)詳解
這篇文章主要為大家介紹了iOS Swift 值類型與引用類型使用區(qū)別基礎(chǔ)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-07-07
iOS開發(fā)上下滑動UIScrollview隱藏或者顯示導航欄的實例
下面小編就為大家分享一篇iOS開發(fā)上下滑動UIScrollview隱藏或者顯示導航欄的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01

