- 效果:拖動(dòng)信息提示數(shù)目按鈕,感覺像是在拉伸按鈕,當(dāng)拖動(dòng)到一定范圍,按鈕(小圓被抽出),松開手小圓會(huì)爆炸。如果抽出小圓后,將小圓移回之前的位置,小圓會(huì)被恢復(fù)
- 核心計(jì)算公式:(見圖中A、B、C、D、O、P點(diǎn)公式)
- 步驟:
- 生成大圓view并設(shè)置屬性(示例是在storyboard中創(chuàng)建,所以下面代碼沒有這步)
- 根據(jù)手勢(shì)拖動(dòng)設(shè)置按鈕移動(dòng)
- 在按鈕原來的位置生成一個(gè)與按鈕一模一樣的小圓view
- 封裝兩圓中心距離計(jì)算方法(勾股定理)
- 根據(jù)兩圓中心距離及一定比例,設(shè)置小圓大小形變
- 利用核心計(jì)算公式,計(jì)算并繪制直線和曲線路徑,通過形狀圖層生成不規(guī)則矩形(計(jì)算方法封裝,需注意兩圓中心距離為0,直接return)
- 當(dāng)兩圓中心距離達(dá)到一定距離后,實(shí)現(xiàn)抽走效果(小圓同時(shí)隱藏)
- 如果松手位置在爆炸范圍圈外,松開手通過核心動(dòng)畫或者imageView播放爆炸幀動(dòng)畫,并將大圓從父控件中移除
- 如果松手位置在爆炸范圍圈內(nèi),通過彈簧效果使大圓重新回到原點(diǎn),并顯示小圓
- VC.m中,要取消autoMask轉(zhuǎn)化為自動(dòng)布局,否則位移會(huì)有問題
[圖片上傳失敗...(image-220148-1511405997537)]
##在BageView.m中
@interface BageView ()
//形狀圖層
@property (nonatomic, weak) CAShapeLayer *shapeLayer;
//小圓控件
@property (nonatomic, weak) UIView *smallCircleView;
@end
@implementation BageView
//懶加載形狀圖層
- (CAShapeLayer *)shapeLayer
{
if (_shapeLayer == nil) {
// 可以根據(jù)路徑生成圖層
CAShapeLayer *layer = [CAShapeLayer layer];
layer.fillColor = [UIColor redColor].CGColor;
[self.superview.layer insertSublayer:layer atIndex:0];//為什么要這樣插入?
_shapeLayer = layer;
}
return _shapeLayer;
}
//對(duì)象初始化
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
[self setUp];
}
return self;
}
//對(duì)象初始化
- (void)awakeFromNib
{
// 初始化
[self setUp];
}
// 初始化操作
- (void)setUp
{
##生成大圓view并設(shè)置屬性(示例是在storyboard中創(chuàng)建,所以下面代碼沒有這步)
// 默認(rèn)背景顏色:紅色
self.backgroundColor = [UIColor redColor];
// 默認(rèn)圓角半徑
self.layer.cornerRadius = self.bounds.size.width * 0.5;
// 設(shè)置字體
self.titleLabel.font = [UIFont systemFontOfSize:12];
// 設(shè)置文字的顏色
[self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
##根據(jù)手勢(shì)拖動(dòng)設(shè)置按鈕移動(dòng)
// 添加pan手勢(shì)
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
[self addGestureRecognizer:pan];
##在按鈕原來的位置生成一個(gè)與按鈕一模一樣的小圓view
// 添加一個(gè)小圓
UIView *smallCircleView = [[UIView alloc] init];
// 尺寸
smallCircleView.frame = self.frame;
// 顏色
smallCircleView.backgroundColor = self.backgroundColor;
// 設(shè)置圓角半徑
smallCircleView.layer.cornerRadius = self.layer.cornerRadius;
// 添加到父控件
[self.superview insertSubview:smallCircleView belowSubview:self];
_smallCircleView = smallCircleView;
}
##根據(jù)手勢(shì)拖動(dòng)設(shè)置按鈕移動(dòng)
- (void)pan:(UIPanGestureRecognizer *)pan
{
// 獲取手指的偏移量
CGPoint transP = [pan translationInView:self];
// 修改形變,移動(dòng)控件的位置
// 修改transform并不會(huì)修改center
// self.transform = CGAffineTransformTranslate(self.transform, transP.x, transP.y);
CGPoint center = self.center;
center.x += transP.x;
center.y += transP.y;
self.center = center;
// 復(fù)位
[pan setTranslation:CGPointZero inView:self];
##封裝兩圓中心距離計(jì)算方法(勾股定理)
// 計(jì)算下兩個(gè)圓心的距離
CGFloat distance = [self distanceWithSmallView:_smallCircleView bigView:self];
##根據(jù)兩圓中心距離及一定比例,設(shè)置小圓大小形變
// 修改小圓的半徑,根據(jù)圓心距離產(chǎn)生一個(gè)比例
CGFloat smallR = self.bounds.size.width * 0.5 - distance / 10.0;
_smallCircleView.bounds = CGRectMake(0, 0, smallR * 2 , smallR * 2);
// 設(shè)置圓角半徑
_smallCircleView.layer.cornerRadius = smallR;
利用核心計(jì)算公式,計(jì)算并繪制直線和曲線路徑,通過形狀圖層生成不規(guī)則矩形(計(jì)算方法封裝,需注意兩圓中心距離為0,直接return)
// 計(jì)算不規(guī)則的矩形路徑
UIBezierPath *path = [self pathWithSmallView:_smallCircleView bigView:self];
if (self.smallCircleView.hidden == NO) { // 當(dāng)小圓沒有顯示的時(shí)候,就不需要描述不規(guī)則的矩形
// 設(shè)置形狀圖層的路徑
self.shapeLayer.path = path.CGPath;
}
##當(dāng)兩圓中心距離達(dá)到一定距離后,實(shí)現(xiàn)抽走效果(小圓同時(shí)隱藏)
// 當(dāng)圓心距離大于60的時(shí)候,吸附效果
if (distance > 60) {
// 隱藏小圓
_smallCircleView.hidden = YES;
// 不規(guī)則的矩形移除父控件
// self.shapeLayer.hidden = YES;
[self.shapeLayer removeFromSuperlayer];
}
##如果松手位置在爆炸范圍圈外,松開手通過核心動(dòng)畫或者imageView播放爆炸幀動(dòng)畫,并將大圓從父控件中移除
if (pan.state == UIGestureRecognizerStateEnded) { // 手指抬起的時(shí)候,需要做判斷
if (distance > 60) {
NSMutableArray *images = [NSMutableArray array];
// 加載gif圖片
for (int i = 1; i <= 8; i++) {
NSString *imageName = [NSString stringWithFormat:@"%d",i];
UIImage *image = [UIImage imageNamed:imageName];
[images addObject:image];
}
// 播放gif圖片
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds];
// 設(shè)置動(dòng)畫數(shù)組
imageView.animationImages = images;
imageView.animationDuration = 1;
[self addSubview:imageView];
// 主動(dòng)播放
[imageView startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.9 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self removeFromSuperview];
});
##如果松手位置在爆炸范圍圈內(nèi),通過彈簧效果使大圓重新回到原點(diǎn),并顯示小圓
}else{ // 還原
// 位置
[UIView animateWithDuration:0.25 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.center = self.smallCircleView.center;
} completion:^(BOOL finished) {
// 小圓顯示
self.smallCircleView.hidden = NO;
}];
}
}
}
利用核心計(jì)算公式,計(jì)算并繪制直線和曲線路徑,通過形狀圖層生成不規(guī)則矩形(計(jì)算方法封裝,需注意兩圓中心距離為0,直接return))
// 計(jì)算不規(guī)則的矩形路徑
- (UIBezierPath *)pathWithSmallView:(UIView *)smallView bigView:(UIView *)bigView
{
// 計(jì)算圓心
CGFloat d = [self distanceWithSmallView:smallView bigView:bigView];
CGFloat y1 = smallView.center.y;
CGFloat x1 = smallView.center.x;
CGFloat r1 = smallView.layer.cornerRadius;
CGFloat y2 = bigView.center.y;
CGFloat x2 = bigView.center.x;
CGFloat r2 = bigView.layer.cornerRadius;
// 如果間距為0,不計(jì)算矩形路徑
if (d == 0) return nil;
// cosθ
CGFloat cosθ = (y2 - y1) / d;
// sinθ
CGFloat sinθ = (x2 - x1) / d;
// A:
CGPoint pointA = CGPointMake(x1 - r1 * cosθ, y1 + r1 * sinθ);
// B:
CGPoint pointB = CGPointMake(x1 + r1 * cosθ, y1 - r1 * sinθ);
// C:
CGPoint pointC = CGPointMake(x2 + r2 * cosθ, y2 - r2 * sinθ);
// D:
CGPoint pointD = CGPointMake(x2 - r2 * cosθ, y2 + r2 * sinθ);
// O:
CGPoint pointO = CGPointMake(pointA.x + d * 0.5 * sinθ, pointA.y + d * 0.5 * cosθ);
// P:
CGPoint pointP = CGPointMake(pointB.x + d * 0.5 * sinθ, pointB.y + d * 0.5 * cosθ);
// 描述路徑
UIBezierPath *path = [UIBezierPath bezierPath];
// nan == null
[path moveToPoint:pointA];
// AB
[path addLineToPoint:pointB];
// BC
// 繪制曲線
[path addQuadCurveToPoint:pointC controlPoint:pointP];
// CD
[path addLineToPoint:pointD];
// DA
[path addQuadCurveToPoint:pointA controlPoint:pointO];
return path;
}
##封裝兩圓中心距離計(jì)算方法(勾股定理)
// 計(jì)算兩個(gè)控件的圓心距離
- (CGFloat)distanceWithSmallView:(UIView *)smallView bigView:(UIView *)bigView
{
CGFloat offsetX = bigView.center.x - smallView.center.x;
CGFloat offsetY = bigView.center.y - smallView.center.y;
return sqrt(offsetX * offsetX + offsetY * offsetY);
}
- (void)setHighlighted:(BOOL)highlighted{}
@end
##VC.m中,要取消autoMask轉(zhuǎn)化為自動(dòng)布局,否則位移會(huì)有問題
- (void)viewDidLoad {
[super viewDidLoad];
// 取消autoMask轉(zhuǎn)化為自動(dòng)布局
self.view.translatesAutoresizingMaskIntoConstraints = NO;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。