美文网首页iOS程序农iOS贝塞尔曲线iOS开发
iOS双波浪效果(CAShaperLayer,一般人我不告诉他)

iOS双波浪效果(CAShaperLayer,一般人我不告诉他)

作者: 会飞的大马猴 | 来源:发表于2017-01-04 18:03 被阅读266次

    贴代码之前我们先了解一下CAShaperLayer吧
    首先这是一个遮罩类,这个东西是画出来的,是一个闭合的曲线,我门可以用这个类来对view来进行各种变形,闭合的区域外都是透明的,根据这个特性,我们就可以来浪了

    补充知识:首先你要知道啥事正弦函数,就是sin,上过高中的,听过课的应该都知道这玩应是干啥的,就一个起点是(0,0)的浪,依稀的记得好像还有个圆一转,就出来了,法科!忘记了,自行google。

    正弦波浪公式:y=Asin(ωx+φ)+k
    -A——振幅,当物体作轨迹符合正弦曲线的直线往复运动时,其值为行程的1/2
    -ω——角速度, 控制正弦周期(单位角度内震动的次数)
    -φ——初相,x=0时的相位;反映在坐标系上则为图像的左右移动
    -k——偏距,反映在坐标系上则为图像的上移或下移

    --------------------------脱裤子,入正题--------------------------

    我写的是一个视图

    需要的类

    CAShapeLayer:遮罩
    CADisplayLink :这个东西跟定时器一样,不过这个东西是在target没刷新1帧才执行一次,所以NSTimer 用起来是不准确的

    需要的属性

    @property (nonatomic, strong) CAShapeLayer *waveShapeLayerA; //?<  遮罩
    @property (nonatomic, strong) CAShapeLayer *waveShapeLayerB; //?< 另外一个遮罩
    @property (nonatomic, strong) UIColor *waveColor;            //?< 颜色
    @property (nonatomic, strong) CADisplayLink *displayLink;    //?< 定时器
    @property (nonatomic, assign) CGFloat offsetX;               //?< A相位
    @property (nonatomic, assign) CGFloat offsetXB;              //?< B相位
    @property (nonatomic, assign) CGFloat waveWidth;             //?< 浪的宽度
    @property (nonatomic, assign) CGFloat waveAmplitude;         //?< 振幅
    @property (nonatomic, strong) UIView *back;                  //?< 另外一个颜色的视图
    //下面这两个我方.h里面了
    @property (nonatomic, assign) CGFloat waveHeight;
    @property (nonatomic, assign) CGFloat waveSpeed;
    (void)wave;
    

    初始化变量

    - (void)layoutSubviews
    {
        _offsetX    = 0;
        _offsetXB   = M_PI/2.0;  //让第2个layer移动1/4个周期
        _waveSpeed  = 0.03;
        _waveHeight = 30;
        _waveWidth  = self.frame.size.width;
        _waveAmplitude = 10;
    }
    

    让它动

    这里创建了两个CAShaperLayer,一个给self 另一个给加在self上的另外一个视图

    - (void)wave {
        /*
         *创建两个layer
         */
        self.waveColor = [UIColor colorWithRed:((arc4random() % 255)/244.0) green:((arc4random() % 255)/244.0) blue:((arc4random() % 255)/244.0) alpha:0.3];
        self.waveShapeLayerA = [CAShapeLayer layer];
        self.waveShapeLayerA.fillColor = self.waveColor.CGColor;
        [self.layer addSublayer:self.waveShapeLayerA];
        
        
        _back = [[UIView alloc]initWithFrame:self.bounds];
        [self addSubview:_back];
        self.waveShapeLayerB = [CAShapeLayer layer];
        self.waveShapeLayerB.fillColor = [UIColor blueColor].CGColor;
        [self.back.layer addSublayer:self.waveShapeLayerB];
        
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(getCurrentWave)];
        [self.displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    }
    

    核心的东西

    这里主要是公式,然后通过x得到所有Y的点绘制成一个闭合的曲线,需要两个,因为我们是两个浪

    - (void)getCurrentWave {
        //offsetX决定x位置,如果想搞明白可以多试几次
        self.offsetX += self.waveSpeed;
        //声明第一条波曲线的路径
        CGMutablePathRef path = CGPathCreateMutable();
        //设置起始点
        CGPathMoveToPoint(path, nil, 0, self.waveHeight);
        
        CGFloat y = 0.f;
        //第一个波纹的公式
        for (float x = 0.f; x <= self.waveWidth ; x++) {
            y = self.waveAmplitude * sin((300 / self.waveWidth) * (x * M_PI / 180) - self.offsetX) + self.waveHeight;
            CGPathAddLineToPoint(path, nil, x, y);
            x++;
        }
        //把绘图信息添加到路径里
        CGPathAddLineToPoint(path, nil, self.waveWidth, self.frame.size.height);
        CGPathAddLineToPoint(path, nil, 0, self.frame.size.height);
        //结束绘图信息
        CGPathCloseSubpath(path);
        
        self.waveShapeLayerA.path = path;
        //释放绘图路径
        CGPathRelease(path);
        
        /*
         *  第二个
         */
        self.offsetXB += self.waveSpeed;
        CGMutablePathRef pathT = CGPathCreateMutable();
        CGPathMoveToPoint(pathT, nil, 0, self.waveHeight+100);
        
        CGFloat yT = 0.f;
        for (float x = 0.f; x <= self.waveWidth ; x++) {
            yT = self.waveAmplitude * sin((300 / self.waveWidth) * (x * M_PI / 180) - self.offsetXB) + self.waveHeight;
            CGPathAddLineToPoint(pathT, nil, x, yT);
        }
        CGPathAddLineToPoint(pathT, nil, self.waveWidth, self.frame.size.height);
        CGPathAddLineToPoint(pathT, nil, 0, self.frame.size.height);
        CGPathCloseSubpath(pathT);
        self.waveShapeLayerB.path = pathT;
        CGPathRelease(pathT);
    }
    

    基本完成

    稍作修饰,就可以出锅了!这里我用了两个slider 分别控制高度 和速度,别的变量也可以。

    - (void)viewDidLoad {
        [super viewDidLoad];
        _wave = [[WaveView alloc]initWithFrame:CGRectMake(50, 400, 300, 300)];
        [self.view addSubview:_wave];
        _wave.layer.masksToBounds = YES;
        _wave.layer.cornerRadius = 150;
        [_wave wave];
        _wave.backgroundColor = [UIColor colorWithRed:((arc4random() % 255)/244.0) green:((arc4random() % 255)/244.0) blue:((arc4random() % 255)/244.0) alpha:0.3];
    }
    - (IBAction)change:(UISlider *)sender {
        CGFloat value = (sender.value * 150);
        _wave.waveHeight = value;
    }
    - (IBAction)speed:(UISlider *)sender {
        CGFloat value = (sender.value * 0.1);
        _wave.waveSpeed = value;
    }
    
    Paste_Image.png

    结构层次

    我们可以看到,两个view分别用layer来实现波浪,这样就双波浪了(好像废话)


    Paste_Image.png

    相关文章

      网友评论

        本文标题:iOS双波浪效果(CAShaperLayer,一般人我不告诉他)

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