iOS仿QQ未读数拖拽效果

作者: SOI | 来源:发表于2017-05-03 16:21 被阅读78次

    在公司的项目基础上,今天也实验了下,QQ未读数拖拽效果。之前就看到网上有同志分析怎么做这个动画,我这里就不写原理了, 大家想看原理的,在网上搜搜就是了,很简单。 我这里只把效果和代码粘贴一下。所涉及到的公司的业务逻辑已经删除掉,此Demo只是用来交流学习使用。

    issue15.gif H文件.png
    #define kBtnWidth self.bounds.size.width
    #define kBtnHeight self.bounds.size.height
    
    
    @interface SouFunNoReadNumIconView()
    
    /** 绘制不规则图形 */
    @property (nonatomic, strong) CAShapeLayer *shapeLayer;
    
    
    
    /** 小圆 */
    @property (nonatomic, strong) UIView  *samllCircleView;
    
    /** 文案 */
    @property (nonatomic, copy) NSString  *noReadStr;
    
    /** 类型 */
    @property (nonatomic, assign) E_RedIconType type;
    
    /** 父视图 */
    @property (nonatomic, weak) UIView  *mySuperView;
    
    /** 记录父视图 */
    @property (nonatomic, weak) UIView  *restSuperView;
    /** 记录原点 */
    @property (nonatomic, assign) CGPoint  originPoint;
    
    /** 大圆脱离小圆的最大距离 */
    @property (nonatomic, assign) CGFloat   maxDistance;
    
    @end
    
    @implementation SouFunNoReadNumIconView
    
    - (instancetype) initWithContentStr:(NSString *)noReadStr andType:(E_RedIconType)type andLRPoint:(CGPoint)leftUpPoint andSuperView:(UIView *)mySuperView{
        
        if (self = [super init]) {
            self.type = type;
            self.noReadStr = noReadStr;
            self.mySuperView = mySuperView;
            
            if (type == E_Normal) {
                CGSize size = [self sizeWithContentStr:noReadStr];
                self.frame = CGRectMake(leftUpPoint.x, leftUpPoint.y, size.width, size.height);
                self.numberOfLines = 1;
                self.backgroundColor = [UtilityHelper colorWithHexString:@"#ff0000"];
                self.textColor = [UIColor whiteColor];
                [self setTextAlignment:NSTextAlignmentCenter];
                [self setFont:[UIFont systemFontOfSize:12.0f]];
                [self setText:noReadStr];
                self.layer.cornerRadius = 9.f;
                self.layer.masksToBounds = YES;
                
                [mySuperView addSubview:self];
                [self setUp];
            }else if (type == E_Normal_Wode) {
                CGSize size = [self sizeWithContentStr:noReadStr];
                self.frame = CGRectMake(leftUpPoint.x, leftUpPoint.y, size.width, size.height);
                self.numberOfLines = 1;
                self.backgroundColor = [UIColor whiteColor];
                self.textColor = [UtilityHelper colorWithHexString:@"#ff2429"];
                [self setTextAlignment:NSTextAlignmentCenter];
                [self setFont:[UIFont systemFontOfSize:12.0f]];
                [self setText:noReadStr];
                self.layer.cornerRadius = 9.f;
                self.layer.masksToBounds = YES;
                
            }else{//留待扩展其他类型
            }
        }
        return self;
    }
    
    - (instancetype) initWithContentStr:(NSString *)noReadStr andType:(E_RedIconType)type andLRPoint:(CGPoint)leftUpPoint{
        if (self = [super init]) {
            self.type = type;
            self.noReadStr = noReadStr;
            
            if (type == E_Normal) {
                CGSize size = [self sizeWithContentStr:noReadStr];
                self.frame = CGRectMake(leftUpPoint.x, leftUpPoint.y, size.width, size.height);
                self.numberOfLines = 1;
                self.backgroundColor = [UtilityHelper colorWithHexString:@"#ff0000"];
                self.textColor = [UIColor whiteColor];
                [self setTextAlignment:NSTextAlignmentCenter];
                [self setFont:[UIFont systemFontOfSize:12.0f]];
                [self setText:noReadStr];
                self.layer.cornerRadius = 9.f;
                self.layer.masksToBounds = YES;
                [self setUp];
            }else if (type == E_Normal_Wode) {
                CGSize size = [self sizeWithContentStr:noReadStr];
                self.frame = CGRectMake(leftUpPoint.x, leftUpPoint.y, size.width, size.height);
                self.numberOfLines = 1;
                self.backgroundColor = [UIColor whiteColor];
                self.textColor = [UtilityHelper colorWithHexString:@"#ff2429"];
                [self setTextAlignment:NSTextAlignmentCenter];
                [self setFont:[UIFont systemFontOfSize:12.0f]];
                [self setText:noReadStr];
                self.layer.cornerRadius = 9.f;
                self.layer.masksToBounds = YES;
                
            }else{//留待扩展其他类型
            }
        }
        return self;
    
    
    }
    
    //根据内容获取size
    - (CGSize)sizeWithContentStr:(NSString *)contentStr{
        
        CGSize size;
        if ([contentStr isEqualToString:@"99+"]) {
            
            size = CGSizeMake(30, 18);
            
        }else if ([contentStr integerValue]<10 &&[contentStr integerValue]>0){
            
            size = CGSizeMake(18, 18);
            
        }else if ([contentStr integerValue]>=10 &&[contentStr integerValue]<=99){
            
            size = CGSizeMake(24, 18);
        
        }else{
            size = CGSizeMake(0, 0);
        }
        
        return size;
        
    }
    
    //小圆
    - (UIView *)samllCircleView
    {
        if (!_samllCircleView) {
            _samllCircleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 18 , 18)];
            _samllCircleView.backgroundColor = [UtilityHelper colorWithHexString:@"#ff0000"];
            [self.superview insertSubview:_samllCircleView belowSubview:self];
        }
        
        return _samllCircleView;
    }
    
    //shapeLayer
    - (CAShapeLayer *)shapeLayer
    {
        if (!_shapeLayer) {
            _shapeLayer = [CAShapeLayer layer];
            _shapeLayer.fillColor = self.backgroundColor.CGColor;
            [self.superview.layer insertSublayer:_shapeLayer below:self.layer];
        }
        
        return _shapeLayer;
    }
    
    //setUp
    - (void)setUp
    {
        self.userInteractionEnabled = YES;
        CGFloat cornerRadius = (kBtnHeight > kBtnWidth ? kBtnWidth / 2.0 : kBtnHeight / 2.0);
       
        _maxDistance = cornerRadius * 6;
        
        
        self.samllCircleView.center = self.center;
        self.samllCircleView.layer.cornerRadius = self.samllCircleView.bounds.size.width / 2.0;
        
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
    
        [self addGestureRecognizer:pan];
        
        UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];
        [self addGestureRecognizer:longPress];
        
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
        [self addGestureRecognizer:tap];
    }
    
    
    - (void)pan:(UIPanGestureRecognizer *)pan
    {
        [self.layer removeAnimationForKey:@"shake"];
    
        if (pan.state == UIGestureRecognizerStateBegan) {
            self.restSuperView = pan.view.superview;
            self.originPoint = pan.view.center;
            self.tableViewBase.utilityTableView.scrollEnabled = NO;
        }
        
        UIWindow *window = [[UIApplication sharedApplication] keyWindow];
        
        CGPoint translation = [pan translationInView:window];
        CGPoint topFloorPoint = [pan.view.superview convertPoint:pan.view.center  toView:window];
        
        CGPoint panPoint = CGPointMake(topFloorPoint.x+ translation.x,
                                       topFloorPoint.y + translation.y);
        
        pan.view.center= panPoint;
        [pan setTranslation:CGPointZero inView:window];
        
        
        if (pan.state == UIGestureRecognizerStateBegan) {
            CGPoint topFloorPoint1 = [pan.view.superview convertPoint:self.samllCircleView.center  toView:window];
            self.samllCircleView.center = topFloorPoint1;
            self.samllCircleView.hidden = NO;
            [window addSubview:self.samllCircleView];
            [window addSubview:self];
        }
        //俩个圆的中心点之间的距离
        CGFloat dist = [self pointToPoitnDistanceWithPoint:self.center potintB:self.samllCircleView.center];
        
        if (dist < _maxDistance) {
            
            CGFloat cornerRadius = (kBtnHeight > kBtnWidth ? kBtnWidth / 2 : kBtnHeight / 2);
            CGFloat samllCrecleRadius = cornerRadius - dist / 10;
            _samllCircleView.bounds = CGRectMake(0, 0, samllCrecleRadius * (2 - 0.5), samllCrecleRadius * (2 - 0.5));
            _samllCircleView.layer.cornerRadius = _samllCircleView.bounds.size.width / 2;
            
            if (_samllCircleView.hidden == NO && dist > 0) {
                //画不规则矩形
                self.shapeLayer.path = [self pathWithBigCirCleView:self smallCirCleView:_samllCircleView].CGPath;
            }
        } else {
            
            [self.shapeLayer removeFromSuperlayer];
            self.shapeLayer = nil;
            
            self.samllCircleView.hidden = YES;
        }
        
        if (pan.state == UIGestureRecognizerStateEnded) {
            
            if (dist > _maxDistance) {
                
                self.tableViewBase.utilityTableView.scrollEnabled = YES;
                [self killAll];
                [SouFunNoReadNumIconView updateDataBaseWithType:self.cleanNoReadtype andMessageid:self.messageId];
                
            } else {
                
                [self.shapeLayer removeFromSuperlayer];
                self.shapeLayer = nil;
                
                [UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
                    self.center = self.samllCircleView.center;
                } completion:^(BOOL finished) {
                    self.samllCircleView.hidden = NO;
                    [self.restSuperView addSubview:self.samllCircleView];
                    [self.restSuperView addSubview:self];
                    self.center = self.originPoint;
                    self.samllCircleView.center = self.originPoint;
                    self.tableViewBase.utilityTableView.scrollEnabled = YES;
    
                }];
            }
        }
    }
    
    //销毁全部控件
    - (void)killAll
    {
        [self removeFromSuperview];
        [self.samllCircleView removeFromSuperview];
        self.samllCircleView = nil;
        [self.shapeLayer removeFromSuperlayer];
        self.shapeLayer = nil;
    }
    
    // 俩个圆心之间的距离
    - (CGFloat)pointToPoitnDistanceWithPoint:(CGPoint)pointA potintB:(CGPoint)pointB
    {
        CGFloat offestX = pointA.x - pointB.x;
        CGFloat offestY = pointA.y - pointB.y;
        CGFloat dist = sqrtf(offestX * offestX + offestY * offestY);
        
        return dist;
    }
    
    //不规则路径
    - (UIBezierPath *)pathWithBigCirCleView:(UIView *)bigCirCleView  smallCirCleView:(UIView *)smallCirCleView
    {
        CGPoint bigCenter = bigCirCleView.center;
        CGFloat x2 = bigCenter.x;
        CGFloat y2 = bigCenter.y;
        CGFloat r2 = bigCirCleView.bounds.size.height / 2.0;
        
        CGPoint smallCenter = smallCirCleView.center;
        CGFloat x1 = smallCenter.x;
        CGFloat y1 = smallCenter.y;
        CGFloat r1 = smallCirCleView.bounds.size.width / 2.0;
        
        // 获取圆心距离
        CGFloat d = [self pointToPoitnDistanceWithPoint:self.samllCircleView.center potintB:self.center];
        CGFloat sinθ = (x2 - x1) / d;
        CGFloat cosθ = (y2 - y1) / d;
        
        // 坐标系基于父控件
        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];
        
        [path moveToPoint:pointA];
        
        [path addLineToPoint:pointB];
       
        [path addQuadCurveToPoint:pointC controlPoint:pointP];
        
        [path addLineToPoint:pointD];
        
        [path addQuadCurveToPoint:pointA controlPoint:pointO];
        
        return path;
    }
    
    //设置长按时候左右摇摆的动画
    - (void)longPress:(UILongPressGestureRecognizer *)longPress
    {
        
        [self.layer removeAnimationForKey:@"shake"];
        if (longPress.state == UIGestureRecognizerStateBegan) {
            //长按左右晃动的幅度大小
            CGFloat shake = 6;
            
            CAKeyframeAnimation *keyAnim = [CAKeyframeAnimation animation];
            keyAnim.keyPath = @"transform.translation.x";
            keyAnim.values = @[@(-shake), @(shake), @(-shake)];
            keyAnim.removedOnCompletion = NO;
            keyAnim.repeatCount = MAXFLOAT;
            //左右晃动一次的时间
            keyAnim.duration = 0.3;
            [self.layer addAnimation:keyAnim forKey:@"shake"];
        }
       
    }
    
    - (void)tap:(UIGestureRecognizer *)tap{
        tap.view.hidden = YES;
        self.samllCircleView.hidden = YES;
        
        NSInteger rowClocn = 3;
        NSMutableArray *boomCells = [NSMutableArray array];
        for (int i = 0; i < rowClocn*rowClocn; ++ i) {
            CGFloat pw = MIN(self.frame.size.width, self.frame.size.height);
            CALayer *shape = [CALayer layer];
            shape.backgroundColor = [UIColor colorWithRed:231/255.0 green:231/255.0 blue:231/255.0 alpha:1.0].CGColor;
            shape.cornerRadius = pw / 2;
            shape.frame = CGRectMake(0, 0, pw, pw);
            [self.layer.superlayer addSublayer: shape];
            [boomCells addObject:shape];
        }
        [self cellAnimations:boomCells withGesture:tap];
    
    }
    
    - (void)cellAnimations:(NSArray*)cells withGesture:(UIGestureRecognizer*)gesture{
        
        for (NSInteger j=0; j<cells.count;j++) {
            CALayer *shape = cells[j];
            shape.position = self.center;
            
            CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
            
            CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
            scaleAnimation.toValue = @0.6;
            
            CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
            pathAnimation.path = [self makeRandomPath: shape AngleTransformation:j].CGPath;
            pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseOut];
            
            animationGroup.animations = @[scaleAnimation,pathAnimation,];
            animationGroup.fillMode = kCAFillModeForwards;
            animationGroup.duration = 0.5;
            animationGroup.removedOnCompletion = NO;
            animationGroup.repeatCount = 1;
            
            [shape addAnimation: animationGroup forKey: @"animationGroup"];
            [self performSelector:@selector(removeLayer:) withObject:shape afterDelay:animationGroup.duration];
        }
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [gesture.view removeFromSuperview];
            [[self class] updateDataBaseWithType:self.cleanNoReadtype andMessageid:self.messageId];
        
        });
        
    }
    
    - (UIBezierPath *) makeRandomPath: (CALayer *) alayer AngleTransformation:(CGFloat)index{
        UIBezierPath *path = [UIBezierPath bezierPath];
        [path moveToPoint:self.center];
        CGFloat dia = self.frame.size.width * (10-(arc4random()%3))/10.0;
        if (index>0) {
            CGFloat angle = index*45*M_PI*2/360;
            CGFloat x = dia*cosf(angle);
            CGFloat y = dia*sinf(angle);
            [path addLineToPoint:CGPointMake(self.center.x + x, self.center.y+y)];
        }else{
            [path addLineToPoint:CGPointMake(self.center.x, self.center.y)];
        }
        
        return path;
    }
    
    -(void)removeLayer:(CALayer*)layer{
        [layer removeAnimationForKey:@"animationGroup"];
        layer.hidden = YES;
        [layer removeFromSuperlayer];
        
    }
    
    +(void)updateDataBaseWithType:(E_CleanNoReadType)type andMessageid:(NSString *)messageid{
      //已经删除未读数具体业务逻辑
    }
    
    @end
    
    

    相关文章

      网友评论

        本文标题:iOS仿QQ未读数拖拽效果

        本文链接:https://www.haomeiwen.com/subject/etzktxtx.html