iOS 仿百度外卖-个人中心(头像波浪效果)

今天带来的是仿百度外卖个人中心的波浪效果,先看下效果图吧

一,项目里用到了两个类:

一个是CADisplayLink类,我用它取代了NSTimer,首先,它是利用刷帧和屏幕频率一样来重绘渲染页面,也就是说每次屏幕刷新的时候就会调用它的响应方法(屏幕一般一秒刷新60次)在绘图中需要重绘时常用它来代替NSTimer,其次,因为NSTimer调度优先级比较低,并不会准时调用,做动画的话会有卡顿的感觉

另一个是CAShapeLayer类,它属于CALayer的子类,通常结合CGPath来绘制不规则矩形图形.

其优点:

    1.渲染效率高渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。

    2.高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。

    3.不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉。

    4.不会出现像素化。当你给CAShapeLayer3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。


 二,下面是功能的实现(直接使用就可以)

先自定义类,基于 UIView(WavesView)

//
//  WavesView.h
//  仿百度外卖-个人中心(头像波浪效果)
//
//  Created by Amydom on 16/12/28.
//  Copyright © 2016年 Amydom. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef void(^WavesBlock)(CGRect myFrame);

@interface WavesView : UIView

/**
 *  浪弯曲度
 */
@property (nonatomic, assign) CGFloat waveCurvature;
/**
 *  浪速
 */
@property (nonatomic, assign) CGFloat waveSpeed;
/**
 *  浪高
 */
@property (nonatomic, assign) CGFloat waveHeight;
/**
 *  实浪颜色
 */
@property (nonatomic, strong) UIColor *realWaveColor;
/**
 *  遮罩浪颜色
 */
@property (nonatomic, strong) UIColor *maskWaveColor;

@property (nonatomic, copy) WavesBlock waveBlock;

@property (nonatomic , assign)CGRect imageFrame;


- (void)stopWaveAnimation;

- (void)startWaveAnimation;

@end

//
//  WavesView.m
//  仿百度外卖-个人中心(头像波浪效果)
//
//  Created by Amydom on 16/12/28.
//  Copyright © 2016年 Amydom. All rights reserved.
//

#import "WavesView.h"

@interface WavesView ()

/**
 *  定时器
    CADisplayLink:利用刷帧和屏幕频率一样来重绘渲染页面,也就是说每次屏幕刷新的时候就会调用它的响应方法(屏幕一般一秒刷新60次),在绘图中需要重绘时常用它来代替NSTimer,因为NSTimer调度优先级比较低,并不会准时调用,做动画的话会有卡顿的感觉
 
*/
@property (nonatomic, strong) CADisplayLink *timer;
/**
 *  实浪动画
    CAShapeLayer:CALayer的子类,通常结合CGPath来绘制不规则矩形图形
    其优点:
    1.渲染效率高渲染快速。CAShapeLayer使用了硬件加速,绘制同一图形会比用Core Graphics快很多。
    2.高效使用内存。一个CAShapeLayer不需要像普通CALayer一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存。
    3.不会被图层边界剪裁掉。一个CAShapeLayer可以在边界之外绘制。你的图层路径不会像在使用Core Graphics的普通CALayer一样被剪裁掉。
    4.不会出现像素化。当你给CAShapeLayer做3D变换时,它不像一个有寄宿图的普通图层一样变得像素化。

 */
@property (nonatomic, strong) CAShapeLayer *realWaveLayer;
/**
 *  遮罩浪动画
 */
@property (nonatomic, strong) CAShapeLayer *maskWaveLayer;
/**
 *  <#Description#>
 */
@property (nonatomic, assign) CGFloat offset;


@end

@implementation WavesView

#pragma mark - 初始化

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setUp];
    }
    return self;
}

-(void)setUp{
    
    //初始化
    self.waveSpeed = 0.5;
    self.waveCurvature = 1.5;
    self.waveHeight = 4;
    self.realWaveColor = [UIColor whiteColor];
    self.maskWaveColor = [[UIColor whiteColor] colorWithAlphaComponent:0.4];
    
    [self.layer addSublayer:self.realWaveLayer];
    [self.layer addSublayer:self.maskWaveLayer];
    
    
}

#pragma mark - lazyload

- (CAShapeLayer *)realWaveLayer{
    
    if (!_realWaveLayer) {
        _realWaveLayer = [CAShapeLayer layer];
        CGRect frame = self.bounds;
        frame.origin.y = frame.size.height-self.waveHeight;
        frame.size.height = self.waveHeight;
        _realWaveLayer.frame = frame;
        _realWaveLayer.fillColor = self.realWaveColor.CGColor;

    }
    
    return _realWaveLayer;
    
}
- (CAShapeLayer *)maskWaveLayer{
    
    if (!_maskWaveLayer) {
         _maskWaveLayer = [CAShapeLayer layer];
        CGRect frame = self.bounds;
        frame.origin.y = frame.size.height-self.waveHeight;
        frame.size.height = self.waveHeight;
        _maskWaveLayer.frame = frame;
        _maskWaveLayer.fillColor = self.maskWaveColor.CGColor;
        
    }
    return _maskWaveLayer;
    
}

- (void)setWaveHeight:(CGFloat)waveHeight{
    
    _waveHeight = waveHeight;
    CGRect frame = self.bounds;
    frame.origin.y = frame.size.height - self.waveHeight;
    frame.size.height = self.waveHeight;
    _realWaveLayer.frame =  _maskWaveLayer.frame =  frame;
    
}
#pragma mark - 动画
- (void)startWaveAnimation{
    
    self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(wave)];
    [self.timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    
    
}

- (void)stopWaveAnimation{
    
    [self.timer invalidate];
    self.timer = nil;
    
    
}

//描述路径,并用CAShapeLayer绘制出来
- (void)wave{
    
    self.offset += self.waveSpeed;
    
    //获取宽,高
    CGFloat width = CGRectGetWidth(self.frame);
    CGFloat height = self.waveHeight;
    
    //真实波浪
    CGMutablePathRef realpath = CGPathCreateMutable();
    CGPathMoveToPoint(realpath, NULL, 0, height);
    CGFloat realY = 0.f;
    
    //遮罩波浪
    CGMutablePathRef maskpath = CGPathCreateMutable();
    CGPathMoveToPoint(maskpath, NULL, 0, height);
    CGFloat maskY = 0.f;
    
    for (CGFloat x = 0.f; x <= width; x++) {
        
        realY = height * sinf(0.01 * self.waveCurvature * x + self.offset * 0.045);
        CGPathAddLineToPoint(realpath, NULL, x, realY);
        maskY = -realY;
        CGPathAddLineToPoint(maskpath, NULL, x, maskY);

    }
    //变化的中间 Y 值
    CGFloat centX = self.bounds.size.width / 2;
    CGFloat centY = height * sinf(0.01 * self.waveCurvature * centX + self.offset * 0.045);
    
    if (self.waveBlock) {
        
        //修改头像view的高度
        CGRect iconFrame = self.imageFrame;
        
        iconFrame.origin.y = CGRectGetHeight(self.frame)-CGRectGetHeight(self.imageFrame) + centY - self.waveHeight;
        
        self.imageFrame = iconFrame;
        
        self.waveBlock(self.imageFrame);
        
    }
    //真实波浪
    CGPathAddLineToPoint(realpath, NULL, width, height);
    CGPathAddLineToPoint(realpath, NULL, 0, height);
    CGPathCloseSubpath(realpath);
    
    //描述路径后利用CAShapeLayer类绘制不规则图形
    self.realWaveLayer.path = realpath;
    self.realWaveLayer.fillColor = self.realWaveColor.CGColor;
    CGPathRelease(realpath);
    
    //遮罩波浪
    CGPathAddLineToPoint(maskpath, NULL, width, height);
    CGPathAddLineToPoint(maskpath, NULL, 0, height);
    CGPathCloseSubpath(maskpath);
    
    //描述路径后利用CAShapeLayer类绘制不规则图形
    self.maskWaveLayer.path = maskpath;
    self.maskWaveLayer.fillColor = self.maskWaveColor.CGColor;
    CGPathRelease(maskpath);

    
    
}

@end

然后是调用,这里就简单的说明下如何调用(在 viewController 里)

首先创建的头像的 image(我是通过懒加载创建的)

- (UIImageView *)iconImageView{
    
    if (!_iconImageView) {
        _iconImageView = [[UIImageView alloc] initWithFrame:CGRectMake(self.WavesView.frame.size.width/2 - 30, 0, 60, 60)];
        _iconImageView.layer.borderColor = [UIColor whiteColor].CGColor;
        _iconImageView.layer.borderWidth = 2;
        _iconImageView.layer.cornerRadius = 30;
    }
    return _iconImageView;
}

然后创建 wavesView,并且把创建好的 image的 frame 传过去

- (void)viewDidLoad {
    
    [super viewDidLoad];
    //创建对线
    self.WavesView = [[WavesView alloc]initWithFrame:CGRectMake(0, 22, self.view.frame.size.width, 150)];
    
    self.WavesView.backgroundColor =[UIColor redColor];
    
    [self.view addSubview:self.WavesView];
    
    [_WavesView addSubview:self.iconImageView];
    
    //这里把头像的 frame 传入到 wavesView里,让其通过 frame来计算该变量
     _WavesView.imageFrame = _iconImageView.frame;
    //防止循环引用
    __weak typeof(self)weakSelf = self;
    
    _WavesView.waveBlock = ^(CGRect imageFrame){
        //修改头像view的frame(时时的通过 block 回调改变的 frame)
        weakSelf.iconImageView.frame = imageFrame;
        
    };
    //开始执行
    [_WavesView startWaveAnimation];
    
}

到这里,波浪形动画就完成了.....大家没事可以多看看动画的实现,对于里面有些东西我也是比较模糊的状态,但是多看多谢,慢慢的你就会发现收获还是有的...






  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值