QQ粘性效果

1.坐標(biāo)點和控制點的計算

粘性計算圖.png

2.新建GooView,繼承自UIButton。

#import "GooView.h"

@interface GooView ()

@property (nonatomic, weak) UIView  *smallCircleView;

@property (nonatomic, assign) CGFloat oriSmallRadius;

@property (nonatomic, weak) CAShapeLayer *shapeLayer;

@end

@implementation GooView

- (CAShapeLayer *)shapeLayer
{
    if (_shapeLayer == nil) {
        
        // 展示不規(guī)則矩形,通過不規(guī)則矩形路徑生成一個圖層
        CAShapeLayer *layer = [CAShapeLayer layer];
        
        _shapeLayer = layer;
        
        layer.fillColor = self.backgroundColor.CGColor;
        
        [self.superview.layer insertSublayer:layer below:self.layer];

    }
    
    return _shapeLayer;
    
}


- (UIView *)smallCircleView
{
    if (_smallCircleView == nil) {
        
        UIView *view = [[UIView alloc] init];
        
        view.backgroundColor = self.backgroundColor;
        
        _smallCircleView = view;
        
        // 小圓添加按鈕的父控件上
        [self.superview insertSubview:view belowSubview:self];
        
    }
    return _smallCircleView;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        
        [self setUp];
    }
    return self;
}
- (void)awakeFromNib
{
    
    [self setUp];
}

#pragma mark - 初始化
- (void)setUp
{
    CGFloat w = self.bounds.size.width;
    
    // 記錄小圓最初始半徑
    _oriSmallRadius = w / 2;
    
    self.layer.cornerRadius = w / 2;
    
    [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    
    self.titleLabel.font = [UIFont systemFontOfSize:12];
    
    // 添加手勢
    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    
    [self addGestureRecognizer:pan];
    
    // 設(shè)置小圓位置和尺寸
    self.smallCircleView.center = self.center;
    self.smallCircleView.bounds = self.bounds;
    self.smallCircleView.layer.cornerRadius = w / 2;
}

// 最大圓心距離
#define kMaxDistance 80

- (void)pan:(UIPanGestureRecognizer *)pan
{
#warning 移動控件位置
    // 獲取手指偏移量
   CGPoint transP = [pan translationInView:self];
    

    // 修改center
    CGPoint center = self.center;
    center.x += transP.x;
    center.y += transP.y;
    
    self.center = center;
    
    // 復(fù)位
    [pan setTranslation:CGPointZero inView:self];

#warning 設(shè)置小圓半徑
    // 顯示后面圓,后面圓的半徑,隨著兩個圓心的距離不斷增加而減小。
    // 計算圓心距離
    CGFloat d = [self circleCenterDistanceWithBigCircleCenter:self.center smallCircleCenter:self.smallCircleView.center];
    
    // 計算小圓的半徑
    CGFloat smallRadius = _oriSmallRadius - d / 10;
    
    // 設(shè)置小圓的尺寸
    self.smallCircleView.bounds = CGRectMake(0, 0, smallRadius * 2, smallRadius * 2);
    
    self.smallCircleView.layer.cornerRadius = smallRadius;
    
#warning 描述不規(guī)則矩形
//    // 繪制不規(guī)則矩形,不能通過繪圖,因為繪圖只能在當(dāng)前控件上畫,超出部分不會顯示。
//    
//    // 兩圓產(chǎn)生距離才需要繪制
//    if (d) {
//       
//        
//    }
    
    // 當(dāng)圓心距離大于最大圓心距離
    if (d > kMaxDistance) { // 可以拖出來
        // 隱藏小圓
        self.smallCircleView.hidden = YES;
        
        // 移除不規(guī)則的矩形
        [self.shapeLayer removeFromSuperlayer];
        self.shapeLayer = nil;
        
    }else if(d > 0 && self.smallCircleView.hidden == NO){ // 有圓心距離,并且圓心距離不大,才需要展示
        // 展示不規(guī)則矩形,通過不規(guī)則矩形路徑生成一個圖層
        
        self.shapeLayer.path = [self pathWithBigCirCleView:self smallCirCleView:self.smallCircleView].CGPath;
    }
    
    
#warning 手指抬起的時候,還原
    if (pan.state == UIGestureRecognizerStateEnded) {
        
        // 當(dāng)圓心距離大于最大圓心距離
        if (d > kMaxDistance) {
            // 展示gif動畫
            
            UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds];
            NSMutableArray *arrM = [NSMutableArray array];
            for (int i = 1; i < 9; i++) {
                UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%d",i]];
                [arrM addObject:image];
            }
            imageView.animationImages = arrM;
            
            imageView.animationRepeatCount = 1;
            
            imageView.animationDuration = 0.5;
            
            [imageView startAnimating];
            
            [self addSubview:imageView];
            
            
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self removeFromSuperview];
            });
            
        }else{
            
            // 移除不規(guī)則矩形
            [self.shapeLayer removeFromSuperlayer];
            self.shapeLayer = nil;
            
            // 還原位置
            [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:0 options:UIViewAnimationOptionCurveLinear animations:^{
                // 設(shè)置大圓中心點位置
                self.center = self.smallCircleView.center;
                
            } completion:^(BOOL finished) {
                // 顯示小圓
                self.smallCircleView.hidden = NO;
            }];
  
        }
        
    }
    
}

// 計算兩個圓心之間的距離
- (CGFloat)circleCenterDistanceWithBigCircleCenter:(CGPoint)bigCircleCenter smallCircleCenter:(CGPoint)smallCircleCenter
{
    CGFloat offsetX = bigCircleCenter.x - smallCircleCenter.x;
    CGFloat offsetY = bigCircleCenter.y - smallCircleCenter.y;
    
    return  sqrt(offsetX * offsetX + offsetY * offsetY);
}

// 描述兩圓之間一條矩形路徑
- (UIBezierPath *)pathWithBigCirCleView:(UIView *)bigCirCleView  smallCirCleView:(UIView *)smallCirCleView
{
    CGPoint bigCenter = bigCirCleView.center;
    CGFloat x2 = bigCenter.x;
    CGFloat y2 = bigCenter.y;
    CGFloat r2 = bigCirCleView.bounds.size.width / 2;
    
    CGPoint smallCenter = smallCirCleView.center;
    CGFloat x1 = smallCenter.x;
    CGFloat y1 = smallCenter.y;
    CGFloat r1 = smallCirCleView.bounds.size.width / 2;

    
    
    // 獲取圓心距離
   CGFloat d = [self circleCenterDistanceWithBigCircleCenter:bigCenter smallCircleCenter:smallCenter];
    
    CGFloat sinθ = (x2 - x1) / d;
    
    CGFloat cosθ = (y2 - y1) / d;
    
    // 坐標(biāo)系基于父控件
    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 / 2 * sinθ , pointA.y + d / 2 * cosθ);
    CGPoint pointP =  CGPointMake(pointB.x + d / 2 * sinθ , pointB.y + d / 2 * cosθ);
    
    UIBezierPath *path = [UIBezierPath bezierPath];
    
    // A
    [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;
    
}


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 動畫分析 當(dāng)前控件既可以顯示圖片,有可以顯示文字,那么我們就可以通過按鈕來最為當(dāng)前的控件. 當(dāng)拖動控件,當(dāng)前控件尺...
    亡靈詛咒閱讀 556評論 0 2
  • QQ粘性效果 實現(xiàn)思路: 1.自定義大圓控件(UIButton)可以顯示背景圖片,和文字 2.讓大圓控件隨著手指移...
    SoManyDumb閱讀 285評論 0 0
  • 制作步驟 1.自定義按鈕控件 設(shè)置背景顏色,設(shè)置layer的cornerRadius屬性,添加手勢,重寫setHi...
    沖破繭縛閱讀 1,410評論 1 7
  • 效果:拖動信息提示數(shù)目按鈕,感覺像是在拉伸按鈕,當(dāng)拖動到一定范圍,按鈕(小圓被抽出),松開手小圓會爆炸。如果抽出小...
    翻這個墻閱讀 484評論 0 0
  • 我想可能又掉到漩渦里了 難過得快要無法呼吸 卻不知道為什么
    琬甯閱讀 266評論 0 0

友情鏈接更多精彩內(nèi)容