QQ消息提醒小球OC 详解

因为项目中需要一个消息提醒,自己学习了一下,然后写了这篇博客,为了自己平时没事的时候可以看一下。代码基本每一行都进行了注释。如果有不对的地方,谢谢指教微笑

不多说了,直接说怎么实现。

实现思路:

1,  新建一个Button类,设置button为圆角。

2,为Button添加 UIPanGestureRecognizer平移手势

3,根据平移手势,设置移动视图所在视图中的移动位置

4,根据移动距离设置触发事件,如果移动距离小于设置移动距离,设置移动后原点的小球,

  根据贝赛尔曲线绘制小球移动路径。若移动距离大于设置距离,移除原点小球,移动路径

5,手势结束,若移动距离小于设置距离,还原,移除移动后原点显示小球,路径。若移动距离大于设置距离,移除所有


下面直接上源代码,代码有详细解释,如有不对,不好之处,谢谢指教:

代码部分:

#import "SmallBallButton.h"


@interface SmallBallButton()<UIGestureRecognizerDelegate>


//小圆

@property (strong,nonatomic)UIView *smallCircleView;

//轨迹layerCALayer的子类

/CALayer的子类。绘图

///http://www.cocoachina.com/ios/20160214/15251.htmlCAShapeLayer的解释

@property (strong,nonatomic)CAShapeLayer *shapeLayer;

//轨迹,贝塞尔曲线获取

@property (strong,nonatomic)UIBezierPath *path;

///图片数组

@property (strong,nonatomic)NSMutableArray *images;


@end


@implementation SmallBallButton



#pragma mark-懒加载在使用的时候初始化

-(UIView*)smallCircleView{

    if (!_smallCircleView) {

        _smallCircleView = [UIViewnew];

   }

    return_smallCircleView;

}

-(CAShapeLayer*)shapeLayer{

    if (!_shapeLayer) {

        _shapeLayer = [CAShapeLayernew];

    }

    return_shapeLayer;

}

-(NSMutableArray*)images{


    if (!_images) {

        _images = [NSMutableArrayarray];

        for (inti=1;i<9; i++) {

           UIImage * image = [UIImageimageNamed:[NSStringstringWithFormat:@"%d",i]];

            [self.imagesaddObject:image];

        }

    }

    return_images;

}

///更新UI

/*layoutSubviews在以下情况下会被调用:


 *1init初始化不会触发layoutSubviews但是是用initWithFrame进行初始化时,当rect的值不为CGRectZero,也会触发

 *2addSubview会触发layoutSubviews

 *3、设置viewFrame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化

 *4、滚动一个UIScrollView会触发layoutSubviews

 *5、旋转Screen会触发父UIView上的layoutSubviews事件

 *6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

 */

-(void)layoutSubviews{

    [superlayoutSubviews];

    [selfinitAll];

    

}


-(void)initAll{

    ///拖拽距离,默认100像素

    if(_maxDistance ==0){

        _maxDistance =100;

    }

   ///初始化Btn属性

    ///设置圆角

    self.layer.cornerRadius =self.bounds.size.width/2;

    self.layer.masksToBounds =YES;

    ///点击事件

    [selfaddTarget:selfaction:@selector(clickBtn)forControlEvents:UIControlEventTouchUpInside];

    ///移动后原点小球

    ///bounds

    self.smallCircleView.bounds = self.bounds;

    ///中心点

    self.smallCircleView.center = self.center;

    self.smallCircleView.backgroundColor = self.backgroundColor;

    self.smallCircleView.layer.cornerRadius = _smallCircleView.bounds.size.width/2;

  

    ///添加到Button底部

    [self.superviewinsertSubview:self.smallCircleViewbelowSubview:self];

    

    ///平移手势

    UIPanGestureRecognizer * pan = [[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(panAction:)];

    [selfaddGestureRecognizer:pan];

}


//在平移手势事件中设置平移后圆的位置

-(void)panAction:(UIPanGestureRecognizer*)panGesture{

    获取所在视图中的平移手势,获取手势初始 x,y相对坐标

    CGPoint point = [panGesturetranslationInView:self.superview];

    ///获取手势移动的x,y,sender.view.center.x是相对于所在视图的X  point.x是每次移动X即移动横坐标。Y

    CGFloat centerX = panGesture.view.center.x+ point.x;

    CGFloatcenterY = panGesture.view.center.y+ point.y;

    ///设置视图移动后所在视图的位置

    panGesture.view.center=CGPointMake(centerX, centerY);

    在所在视图中设置平移值,设置影响平移速度

    [panGesture setTranslation:CGPointMake(0,0)inView:self.superview];

   

    //计算移动距离

    CGFloat distance = [selfgetDistanceFromPointA:self.centerToPointB:_smallCircleView.center];

   

    if (distance <_maxDistance) {

       

        ///每当distance < _maxDistance,都设置_smallCircleView不隐藏

         _smallCircleView.hidden =NO;

        ///根据按钮大小设置小球的大小,这里设置初始值为按钮大小的一半

        CGFloat radius = panGesture.view.bounds.size.width> panGesture.view.bounds.size.height? panGesture.view.bounds.size.width*0.5:panGesture.view.bounds.size.height*0.5;

        ///设置小球的大小,根据距离改变大小

        _smallCircleView.bounds =CGRectMake(0,0, radius-distance/10, radius-distance/10);

        ///根据大小设置圆角

        _smallCircleView.layer.cornerRadius= (radius-distance/10)*0.5;

        

        if(_smallCircleView.hidden==NO&& distance>0){

           

            ///设置填充颜色

            _shapeLayer.fillColor =self.backgroundColor.CGColor;

            

            ///设置贝塞尔曲线绘图路径

            self.shapeLayer.path = [self pathWithBigCirCleView:selfsmallCirCleView:_smallCircleView].CGPath;

            将绘制图形插入视图

            [self.superview.layerinsertSublayer:_shapeLayerbelow:_smallCircleView.layer];


        }


    }else{

        [_shapeLayerremoveFromSuperlayer];

        _shapeLayer =nil;

        _smallCircleView.hidden =YES;


    }

    ///如果平移结束

    if(panGesture.state ==UIGestureRecognizerStateEnded){

        if(distance >_maxDistance){

           NSLog(@"拖动 ->销毁了");

            [selfstartDestroyAnimations];

            [selfallKill];

        }else{

            [_shapeLayerremoveFromSuperlayer];

            _shapeLayer =nil;

            ///设置弹簧效果动画,效果UIViewAnimationOptionCurveEaseInOut缓慢->加速->缓慢

            [UIViewanimateWithDuration:0.3delay:0usingSpringWithDamping:0.2initialSpringVelocity:1options:UIViewAnimationOptionCurveEaseInOutanimations:^{

                ///还原

                self.center =_smallCircleView.center;

            } completion:^(BOOLfinished) {

                _smallCircleView.hidden =NO;

            }];

            

        }

    }

   


}

///计算相对距离

-(CGFloat)getDistanceFromPointA:(CGPoint)PointA ToPointB:(CGPoint)PointB{

    CGFloat x = PointA.x-PointB.x;

    CGFloaty = PointA.y- PointB.y;

    returnsqrtf(x*x + y*y);

}


按钮点击事件

-(void)clickBtn{

    

    self.clickName(self);

    [selfstartDestroyAnimations];

    [selfallKill];

}

///UIBezierPath 顾名思义,这是用贝塞尔曲线的方式来构建一段弧线

-(UIBezierPath*)pathWithBigCirCleView:(UIView*)bigCirCleView smallCirCleView:(UIView*)smallCirCleView

{

    //获取button的相对坐标x,y

    CGPoint bigCenter = bigCirCleView.center;

    CGFloat bigX = bigCenter.x;

    CGFloat bigY = bigCenter.y;

    

    //根据bounds设置大球的圆角

    CGFloat bigRadius = bigCirCleView.bounds.size.width*0.5;

    

    ///获取小球的相对坐标 x,y

    CGPoint smallCenter = smallCirCleView.center;

    CGFloat smallX = smallCenter.x;

    CGFloatsmallY = smallCenter.y;

    //根据bounds设置小球的圆角

    CGFloat smallRadius = smallCirCleView.bounds.size.width*0.5;

   

    ///大小球距离

    CGFloat d = [selfgetDistanceFromPointA:smallCenterToPointB:bigCenter];

    

    ///三角形bigX-smallX横线 bigY-smallY三角形竖线

    CGFloat sina = (bigX-smallX)/d;

    CGFloat cosa = (bigY-smallY)/d;

    ///计算小球中心点为原点第一象限的点

    CGPoint pointA =CGPointMake(smallX-smallRadius*cosa, smallY+smallRadius*sina);

    ///计算小球中心店为原点第三象限的点

    CGPoint pointB =CGPointMake(smallX+smallRadius*cosa, smallY-smallRadius*sina);

    ///同上,打球第一,第三象限的点(一:C,三:D

    CGPoint pointC =CGPointMake(bigX+bigRadius*cosa, bigY-bigRadius*sina);

    CGPoint pointD =CGPointMake(bigX-bigRadius*cosa, bigY+bigRadius*sina);

    //计算小球第四象限的点,(大概是距离大球最近的点)

    CGPoint pointO =CGPointMake(pointA.x+d/2*sina, pointA.y+d/2*cosa);

    //计算大球第四象限的点(大概是距离小球最远的点)

    CGPoint pointP =CGPointMake(pointB.x+d/2*sina, pointB.y+d/2*cosa);

    

    //使用UIBezierPath类可以创建基于矢量的路径,这个类在UIKit中。此类是Core Graphics框架关于path的一个封装。使用此类可以定义简单的形状,如椭圆或者矩形,或者有多个直线和曲线段组成的形状贝赛尔曲线

    UIBezierPath *path = [UIBezierPathbezierPath];

    

    // A 设置初始线段的起点

    [path moveToPoint:pointA];

    // AB 设置先前的终点,之后的起点

    [path addLineToPoint:pointB];

    // 绘制BC曲线,起点B

    [path addQuadCurveToPoint:pointCcontrolPoint:pointP];

    

    // CD 绘制 CD的直线

    [path addLineToPoint:pointD];

    // 绘制DA曲线

    [path addQuadCurveToPoint:pointAcontrolPoint:pointO];

    return path;

    

}

移除动画(UIImageView的动画,连续播放图片组成动画)

-(void)startDestroyAnimations

{

    UIImageView *animaImageView = [[UIImageViewalloc]initWithFrame:self.frame];

    ///设置用作动画的图片数组

    animaImageView.animationImages=self.images;//images是装image的数组

    ///指定重复动画的次数。默认值为0,指定无限期重复动画。

    animaImageView.animationRepeatCount=1;

    ///动画时间

    animaImageView.animationDuration=0.5;

    开始动画

    [animaImageView startAnimating];

    ///添加到使用控制器

    [self.superviewaddSubview:animaImageView];

}

///移除所有

-(void)allKill

{

    [selfremoveFromSuperview];

    [_smallCircleViewremoveFromSuperview];

    [_shapeLayerremoveFromSuperlayer];

    _smallCircleView =nil;

    _shapeLayer =nil;

}


@end


效果图:

效果图:


项目代码:点我下载Demo







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值