iOS仿QQ未读数拖拽效果

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • 公司的资产有很多个方面。人力资产是最为重要的一个方面。那么哪些人是公司人力资产中最重要的呢? 公司最重要的资产是那...
    西风瘦马_Horsken阅读 302评论 0 1
  • 又到招生季,今年秋季我们将要迎接一百多位新生,这个数字不断被刷新,孩子越来越多,对幼儿园来说并非好事,对管理...
    超群老师阅读 586评论 0 0
  • day1 下定决心,北海出发。 7点闹铃一响,我一骨碌爬起来。赶紧吃早饭,坐公交,出发。 大年初一,路上车很少,我...
    身居井隅阅读 395评论 0 2
  • 苗族同胞自古以来,拥有自己的历法,也称为苗历,“苗年”就是每年的苗历之首日,类似我们汉族的“春节”,是苗族同胞最隆...
    践行者张恺阅读 1,176评论 3 7
  • 【蓝政文化收稿收网编】 贴吧文章纲手 千20起,要老手,靠谱来戳 开头文 各种类型千30起! 短篇 女频婚恋总裁虐...
    千瑾言阅读 470评论 0 0