iOS QQ粘性布局

来源:互联网 发布:瘦身 知乎 编辑:程序博客网 时间:2024/04/28 03:57

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
原创粉丝点击