【iOS】储水罐波纹样式button 以及 随机路线的泡泡

话说又有这么一个需求……产品想让项目中增加一个按钮:一个点击了之后会有波纹上升的按钮。在波纹到达顶端的时候还会有三个泡泡出现,以随机的路线不同的速度漂浮到固定的一个点……
好吧,你赢了。
【iOS】储水罐波纹样式button 以及 随机路线的泡泡_第1张图片

先来完成这个波纹按钮


/*
 正弦函数
 y =Asin(ωx+φ)+C
 A 表示振幅,也就是使用这个变量来调整波浪的高度
 ω表示周期,也就是使用这个变量来调整在屏幕内显示的波浪的数量
 φ表示波浪横向的偏移,也就是使用这个变量来调整波浪的流动
 C表示波浪纵向的位置,也就是使用这个变量来调整波浪在屏幕中竖直的位置。
 */
 
 {
    UIImage *_img;
    BOOL _once;
}

@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) CADisplayLink *waveDisplaylink;
@property (nonatomic, strong) CAShapeLayer *firstWaveLayer;
@property (nonatomic, strong) CAShapeLayer *secondWaveLayer;
 @property (nonatomic) CGFloat waveA; //水纹振幅    表示上面的A
@property (nonatomic) CGFloat waveW;//水纹周期  表示上面的ω
@property (nonatomic) CGFloat offsetX; //位移   表示上面的φ
@property (nonatomic) CGFloat currentK; //当前波浪高度Y   表示上面的C
@property (nonatomic) CGFloat waveSpeed;//水纹速度   表示波浪流动的速度
@property (nonatomic) CGFloat waterWaveWidth; //水纹宽度
@property (nonatomic, strong) UIColor *firstWaveColor; //波浪的颜色

属性大致就是这些。当按钮被点击的时候显示波浪

//按钮被点击
-(void)viewDidClicked
{
    //动画效果下只能点击一次
    if (_once) {
        return;
    }
    
    if (self.animation) {
        //创建波浪
        _once = YES;
        [self createWave];
    }else{
        //回调
        if (self.buttonDidClick) {
            self.buttonDidClick();
        }
        if ([self.delegate respondsToSelector:@selector(waveButtonDidClicked)]) {
            [self.delegate waveButtonDidClicked];
        }
    }
}

#pragma mark - 创建波浪
-(void)createWave{
    //设置波浪的宽度
    self.waterWaveWidth = self.bounds.size.width;
    //设置波浪的颜色
    self.firstWaveColor = RGBA(250, 188, 16, 1);
    //设置波浪的速度
    self.waveSpeed = 0.4/M_PI;
    
    //初始化layer
    if (_firstWaveLayer == nil) {
        //初始化
        _firstWaveLayer = [CAShapeLayer layer];
        //设置闭环的颜色
        _firstWaveLayer.fillColor = _firstWaveColor.CGColor;
        [self.layer addSublayer:_firstWaveLayer];
    }
    //这里设置两个layer叠加起来丰富层次
    if (self.secondWaveLayer == nil) {
        //初始化
        self.secondWaveLayer = [CAShapeLayer layer];
        //设置闭环的颜色
        self.secondWaveLayer.fillColor = _firstWaveColor.CGColor;
        [self.layer addSublayer:self.secondWaveLayer];
    }
    
    [self bringSubviewToFront:self.titleLabel];
    [self bringSubviewToFront:self.imageView];
    
    //设置波浪流动速度
    self.waveSpeed = 0.5;
    //设置振幅
    self.waveA = 2;
    //设置周期
    self.waveW = 1/20.0;
    //设置波浪纵向位置
    self.currentK = self.frame.size.height;//屏幕居中
    //启动定时器
    self.waveDisplaylink = [CADisplayLink displayLinkWithTarget:self selector:@selector(getCurrentWave:)];
    [self.waveDisplaylink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

//定时器调用的方法
-(void)getCurrentWave:(CADisplayLink *)displayLink
{
    //实时的位移
    self.offsetX += self.waveSpeed;
    if (self.currentK > 0) {
        self.currentK --;
        //使波浪动起来
        [self setCurrentFirstWaveLayerPath];
        [self setCurrentSecondWaveLayerPath];
    } else {
    	//波浪到达了顶点
        self.backgroundColor = self.firstWaveColor;
        
        //移除两个波浪层
        [self.firstWaveLayer removeFromSuperlayer];
        [self.secondWaveLayer removeFromSuperlayer];
        
        //销毁计时器
        [_waveDisplaylink invalidate];
        
        //回调
        if (self.buttonDidClick) {
            self.buttonDidClick();
        }
        if ([self.delegate respondsToSelector:@selector(waveButtonDidClicked)]) {
            [self.delegate waveButtonDidClicked];
        }
    }
}

//创建波浪路径,其实这两个方法也可以写成一个通过参数调整的方法,不过当时懒……
-(void)setCurrentFirstWaveLayerPath
{
    //创建一个路径
    UIBezierPath *path = [UIBezierPath new];
    CGFloat y = self.currentK;
    //将点移动到 x=0,y=currentK的位置
    [path moveToPoint:CGPointMake(0, y)];
    for (NSInteger x = 0.0f; x<=self.waterWaveWidth; x++) {
        //正玄波浪公式
        y = self.waveA * sin(self.waveW * x + self.offsetX)+self.currentK;
        //将点连成线
        [path addLineToPoint:CGPointMake(x, y)];
    }
    [path addLineToPoint:CGPointMake(self.waterWaveWidth, self.frame.size.height)];
    [path addLineToPoint:CGPointMake(0, self.frame.size.height)];
    self.firstWaveLayer.path = path.CGPath;
    
}

-(void)setCurrentSecondWaveLayerPath
{
    //创建一个路径
    UIBezierPath *path = [UIBezierPath new];
    CGFloat y = self.currentK;
    //将点移动到 x=0,y=currentK的位置
    [path moveToPoint:CGPointMake(0, y)];
    for (NSInteger x = 0.0f; x<=self.waterWaveWidth; x++) {
        //正玄波浪公式
        y = (self.waveA+2) * sin((self.waveW) * x - self.offsetX + 10)+self.currentK;
        //将点连成线
        [path addLineToPoint:CGPointMake(x, y)];
    }
    [path addLineToPoint:CGPointMake(self.waterWaveWidth, self.frame.size.height)];
    [path addLineToPoint:CGPointMake(0, self.frame.size.height)];
    self.secondWaveLayer.path = path.CGPath;
}

这样带有波浪的按钮就完成了。继续做按钮完成时出现的泡泡。

//泡泡视图的初始化方法,参数是泡泡的起始点和终点
-(instancetype)initWithFrame:(CGRect)frame startPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint{
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor clearColor];
        self.startPoint = startPoint;
        self.endPoint = endPoint;
        //泡泡是默认隐藏的
        [self addSubview:self.bubble1];
        [self addSubview:self.bubble2];
        [self addSubview:self.bubble3];
        [self initPath];
        _bubbleArray = @[self.bubble1, self.bubble2, self.bubble3];
    }
    return self;
}

//创建路径
-(void)initPath{
    for (int i=1; i<4; i++) {
        //第一条路径
        UIBezierPath *path = [UIBezierPath bezierPath];
        //移动到起点
        [path moveToPoint:self.startPoint];
        //随机一个控制点,x最大是屏幕宽-小球的宽度,这样才能显示小球
        CGFloat x1 = arc4random_uniform(ScreenWidth/2)+ScreenWidth/2-24;
        //转折点在起点终点中间位置,上下波动不超过30
        CGFloat y1 = arc4random_uniform(30)+(self.startPoint.y-self.endPoint.y)/2;
        //添加控制点
        [path addQuadCurveToPoint:self.endPoint controlPoint:CGPointMake(x1, y1)];
        //设置曲线类型
        path.lineJoinStyle = kCGLineJoinRound;

        if (i==1) {
            self.path1 = path;
        }else if (i==2){
            self.path2 = path;
        }else{
            self.path3 = path;
        }
    }
    _pathArray = @[self.path1, self.path2, self.path3];
}

这样泡泡和路径都设置好了,只要在波纹按钮升到定点的回调方法中调用泡泡视图的show。

-(void)show{
    for (int i=0; i<_bubbleArray.count; i++) {
        UIImageView *bubble = _bubbleArray[i];
        CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        //设置路径
        animation.path = [_pathArray[i] CGPath];
        //设置重复次数
        animation.repeatCount = 1;
        //动画时长
        animation.duration = 1+i*0.25;
        animation.delegate = self;
        //完成后不移除
        animation.removedOnCompletion = NO;
        //
        animation.fillMode = kCAFillModeForwards;
        [animation setValue:@(i) forKey:@"count"];
        
        //添加动画
        bubble.alpha = 1;
        [bubble.layer addAnimation:animation forKey:@""];
    }
}

最后在动画结束的协议方法中将泡泡视图隐藏掉:

-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    if (flag) {
        NSInteger count = [[anim valueForKey:@"count"] integerValue];
        UIImageView *bubble = _bubbleArray[count];
        bubble.alpha = 0;
        if (count == 2) {
            //回调
            if (self.animationDidEnd) {
                self.animationDidEnd();
            }
        }
    }
}

就完成啦!

你可能感兴趣的:(ios技术点,iosUI)