iOS QQ粘性布局

Demo下载地址:http://download.csdn.net/download/u010981736/9964836

iOS 仿照QQ未读消息提醒数字的粘性布局,实现了和QQ未读消息一样的功能,拖拽的时候会有粘性效果,在一定范围内拖拽松手还会回到原来的位置,超过一定距离之后就会播放一个动画。

效果图:
这里写图片描述

核心代码:

//
//  BageValueBtn.m
//  QQ粘性布局
//
//  Created by llkj on 2017/9/5.
//  Copyright © 2017年 LayneCheung. All rights reserved.
//

#import "BageValueBtn.h"

@interface BageValueBtn()

@property (nonatomic, weak)  UIView *smallCircle;
@property (nonatomic, weak)  CAShapeLayer *shap;


@end
@implementation BageValueBtn


-(void)awakeFromNib{

    [super 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] init];
    smallCircle.frame = self.frame;
    smallCircle.backgroundColor = self.backgroundColor;
    smallCircle.layer.cornerRadius = self.layer.cornerRadius;
    self.smallCircle = smallCircle;
    [self.superview insertSubview:smallCircle belowSubview:self];



}


//计算两个圆之间的距离
- (CGFloat)distanceWithSmallCircle:(UIView *)smallCircle bigCircle:(UIView *)bigCircle{

    //X轴偏移量
    CGFloat offsetX = bigCircle.center.x - smallCircle.center.x;
    //Y轴偏移量
    CGFloat offsetY = bigCircle.center.y - smallCircle.center.y;

    return  sqrtf(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)pan:(UIPanGestureRecognizer *)pan{

    //frame,center,transform.

    //移动.
    CGPoint transP = [pan translationInView:self];
    //修改transform值,并没有去修改center,它修改的frame
    //    self.transform = CGAffineTransformTranslate(self.transform, transP.x, transP.y);

    CGPoint center =  self.center;
    center.x += transP.x;
    center.y += transP.y;
    self.center = center;

    //复位
    [pan setTranslation:CGPointZero inView:self];
    //两个圆之间的距离
    CGFloat distance = [self distanceWithSmallCircle:self.smallCircle bigCircle:self];

    //让小圆的半径减去距离的比例
    //获取小圆的半径
    CGFloat smallR = self.bounds.size.width * 0.5;
    smallR = smallR - distance / 10.0;
    //要重设置小圆的尺寸
    self.smallCircle.bounds = CGRectMake(0, 0, smallR * 2, smallR * 2);
    //重新设置小圆的圆角
    self.smallCircle.layer.cornerRadius = smallR;


    //不规则的路径.

    //如果小圆显示的时候再创建
    if(self.smallCircle.hidden == NO){
        UIBezierPath *path = [self pathWithSmallCircle:self.smallCircle bigCircle:self];
        self.shap.path = path.CGPath;
    }


    //如果两个圆之间的距离超过某个范围.让小圆隐藏,shap移除
    if(distance > 60){
        self.smallCircle.hidden = YES;
        [self.shap removeFromSuperlayer];
    }
    //当手指松开时,如果发现两个圆之间距离小于某个值时,大圆复位.
    if(pan.state == UIGestureRecognizerStateEnded){
        //如果发现两个圆之间距离小于某个值时,大圆复位.
        if (distance < 60) {
            //移除形状
            [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];

            NSMutableArray *imageArray = [NSMutableArray array];
            for (int i = 0; i < 8; ++i) {
                NSString *imageName = [NSString stringWithFormat:@"%d",i + 1];
                UIImage *image = [UIImage imageNamed:imageName];
                [imageArray addObject:image];
            }

            imageV.animationImages = imageArray;
            //设置动画的执行时长
            [imageV setAnimationDuration:1];
            //开始动画
            [imageV startAnimating];
            [self addSubview:imageV];

            //一秒钟后.把当前的按钮从父控件当中移.
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                //把当前的按钮从父控件当中移.
                [self removeFromSuperview];
            });


        }

    }




}


//取消高亮状态
-(void)setHighlighted:(BOOL)highlighted{
}

/*
 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.
 - (void)drawRect:(CGRect)rect {
 // Drawing code
 }
 */

@end
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值