UI定制 - 高仿百度外卖顶部波浪效果

高仿百度外卖顶部波浪效果

1 - 代码示例

// - WavesView.h

复制代码
 1 #import <UIKit/UIKit.h>
 2 typedef void(^WavesBlock)(CGRect myFrame);
 3 
 4 @interface WavesView : UIImageView
 5 
 6 @property (nonatomic, assign) CGFloat waveCurvature; // 几叠浪
 7 @property (nonatomic, assign) CGFloat waveSpeed;     // 浪速
 8 @property (nonatomic, assign) CGFloat waveHeight;    // 浪高
 9 @property (nonatomic, strong) UIColor *realWaveColor;// 实浪颜色
10 @property (nonatomic, strong) UIColor *maskWaveColor;// 遮罩浪颜色
11 
12 @property (nonatomic, copy) WavesBlock waveBlock;
13 @property (nonatomic, assign)CGRect imageFrame;
14 
15 - (void)stopWaveAnimation;  // 开始起浪
16 - (void)startWaveAnimation; // 停止波浪
17 
18 @end
复制代码

// - WavesView.m

复制代码
  1 #import "WavesView.h"
  2 #define MainScreen_W [UIScreen mainScreen].bounds.size.width
  3 @interface WavesView ()
  4 
  5 // 定时器
  6 // CADisplayLink:利用刷帧和屏幕频率一样来重绘渲染页面,也就是说每次屏幕刷新的时候就会调用它的响应方法(屏幕一般一秒刷新60次)
  7 // 在绘图中需要重绘时常用它来代替 NSTimer,因为 NSTimer 调度优先级比较低,并不会准时调用,做动画的话会有卡顿的感觉
  8 @property (nonatomic, strong) CADisplayLink *timer;
  9 
 10 
 11 // 实浪动画
 12 // CAShapeLayer:CALayer 的子类,通常结合 CGPath 来绘制不规则矩形图形
 13 // 优点:
 14 // 1.渲染效率高渲染快速。CAShapeLayer 使用了硬件加速,绘制同一图形会比用 Core Graphics 快很多
 15 // 2.高效使用内存。一个 CAShapeLayer 不需要像普通 CALayer 一样创建一个寄宿图形,所以无论有多大,都不会占用太多的内存
 16 // 3.不会被图层边界剪裁掉。一个 CAShapeLayer 可以在边界之外绘制。你的图层路径不会像在使用 Core Graphics 的普通 CALayer 一样被剪裁掉
 17 // 4.不会出现像素化。当你给 CAShapeLayer 做 3D 变换时,它不像一个有寄宿图的普通图层一样变得像素化
 18 @property (nonatomic, strong) CAShapeLayer *realWaveLayer;
 19 
 20 
 21 // 遮罩
 22 @property (nonatomic, strong) CAShapeLayer *maskWaveLayer;
 23 @property (nonatomic, assign) CGFloat offset;
 24 
 25 @end
 26 
 27 @implementation WavesView
 28 
 29 - (instancetype)initWithFrame:(CGRect)frame{
 30     self = [super initWithFrame:frame];
 31     if (self) {
 32         [self setUp];
 33     }
 34     return self;
 35 }
 36 
 37 -(void)setUp{
 38 
 39     // 初始化
 40     self.waveSpeed = 0.8;
 41     self.waveCurvature = 1.5;
 42     self.waveHeight = 6.5;
 43     self.realWaveColor = [UIColor whiteColor];
 44     self.maskWaveColor = [[UIColor whiteColor] colorWithAlphaComponent:0.4];
 45 
 46     [self.layer addSublayer:self.realWaveLayer];
 47     [self.layer addSublayer:self.maskWaveLayer];
 48 
 49 }
 50 
 51 #pragma mark - lazyload
 52 - (CAShapeLayer *)realWaveLayer{
 53 
 54     if (!_realWaveLayer) {
 55         _realWaveLayer = [CAShapeLayer layer];
 56         CGRect frame = self.bounds;
 57         frame.origin.y = frame.size.height-self.waveHeight;
 58         frame.size.height = self.waveHeight;
 59         _realWaveLayer.frame = frame;
 60         _realWaveLayer.fillColor = self.realWaveColor.CGColor;
 61 
 62     }
 63 
 64     return _realWaveLayer;
 65 
 66 }
 67 - (CAShapeLayer *)maskWaveLayer{
 68 
 69     if (!_maskWaveLayer) {
 70         _maskWaveLayer = [CAShapeLayer layer];
 71         CGRect frame = self.bounds;
 72         frame.origin.y = frame.size.height-self.waveHeight;
 73         frame.size.height = self.waveHeight;
 74         _maskWaveLayer.frame = frame;
 75         _maskWaveLayer.fillColor = self.maskWaveColor.CGColor;
 76     }
 77     return _maskWaveLayer;
 78 
 79 }
 80 
 81 - (void)setWaveHeight:(CGFloat)waveHeight{
 82 
 83     _waveHeight = waveHeight;
 84     CGRect frame = self.bounds;
 85     frame.origin.y = frame.size.height - self.waveHeight;
 86     frame.size.height = self.waveHeight;
 87     _realWaveLayer.frame =  _maskWaveLayer.frame =  frame;
 88 }
 89 
 90 #pragma mark - 动画
 91 - (void)startWaveAnimation{
 92 
 93     self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(wave)];
 94     [self.timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
 95 }
 96 
 97 - (void)stopWaveAnimation{
 98 
 99     [self.timer invalidate];
100     self.timer = nil;
101 }
102 
103 // 描述路径,并用 CAShapeLayer 绘制出来
104 - (void)wave{
105 
106     self.offset += self.waveSpeed;
107 
108     // 获取宽,高
109     CGFloat width = CGRectGetWidth(self.frame);
110     CGFloat height = self.waveHeight;
111 
112     // 真实波浪
113     CGMutablePathRef realpath = CGPathCreateMutable();
114     CGPathMoveToPoint(realpath, NULL, 0, height);
115     CGFloat realY = 0.f;
116 
117     // 遮罩波浪
118     CGMutablePathRef maskpath = CGPathCreateMutable();
119     CGPathMoveToPoint(maskpath, NULL, 0, height);
120     CGFloat maskY = 0.f;
121 
122     for (CGFloat x = 0.f; x <= width; x++) {
123 
124         realY = height * sinf(0.01 * self.waveCurvature * x + self.offset * 0.045);
125         CGPathAddLineToPoint(realpath, NULL, x, realY);
126         maskY = -realY;
127         CGPathAddLineToPoint(maskpath, NULL, x, maskY);
128 
129     }
130     // 变化的中间 Y 值
131     CGFloat centX = self.bounds.size.width / 2;
132     CGFloat centY = height * sinf(0.01 * self.waveCurvature * centX + self.offset * 0.045);
133 
134     if (self.waveBlock) {
135 
136         // 修改头像 view 的高度
137         CGRect iconFrame = self.imageFrame;
138 
139         // MainScreen_W/4.68------调整浮动 UI 的高度
140         iconFrame.origin.y = CGRectGetHeight(self.frame)-CGRectGetHeight(self.imageFrame) + centY - self.waveHeight-MainScreen_W/4.68;
141 
142         self.imageFrame = iconFrame;
143         self.waveBlock(self.imageFrame);
144     }
145     // 真实波浪
146     CGPathAddLineToPoint(realpath, NULL, width, height);
147     CGPathAddLineToPoint(realpath, NULL, 0, height);
148     CGPathCloseSubpath(realpath);
149 
150     // 描述路径后利用 CAShapeLayer 类绘制不规则图形
151     self.realWaveLayer.path = realpath;
152     self.realWaveLayer.fillColor = self.realWaveColor.CGColor;
153     CGPathRelease(realpath);
154 
155     // 遮罩波浪
156     CGPathAddLineToPoint(maskpath, NULL, width, height);
157     CGPathAddLineToPoint(maskpath, NULL, 0, height);
158     CGPathCloseSubpath(maskpath);
159 
160     // 描述路径后利用 CAShapeLayer 类绘制不规则图形
161     self.maskWaveLayer.path = maskpath;
162     self.maskWaveLayer.fillColor = self.maskWaveColor.CGColor;
163     CGPathRelease(maskpath);
164 }
165 
166 @end 
复制代码

2 - 代码示例:如何使用

复制代码
 1 #import "ViewController.h"
 2 #import "WavesView.h"
 3 @implementation ViewController
 4 
 5 - (void)viewDidLoad {
 6     [super viewDidLoad];
 7     self.view.backgroundColor = [UIColor whiteColor];
 8 
 9     // 初始化 WavesView
10     WavesView *wV = [[WavesView alloc] initWithFrame:CGRectMake(0, 80, self.view.frame.size.width, 200)];
11     wV.backgroundColor = [UIColor redColor];
12     [self.view addSubview:wV];
13     [wV startWaveAnimation];
14 
15     // 自定制
16     wV.waveCurvature = 1.3;
17     wV.waveSpeed = 1.2;
18     wV.realWaveColor = [UIColor blueColor];
19     wV.maskWaveColor = [UIColor yellowColor];
20     wV.waveHeight = 11;
21 
22     // 随波浮动
23     // 若要调整浮动 UI 的初始位置,在 WavesView 类中的 wave 方法里修改
24     UILabel *abel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 40)];
25     abel.text = @"Bruce Lee";
26     abel.font = [UIFont systemFontOfSize:30.0];
27     abel.textAlignment = NSTextAlignmentCenter;
28     abel.textColor = [UIColor whiteColor];
29     [wV addSubview:abel];
30     wV.imageFrame = abel.frame;
31     wV.waveBlock = ^(CGRect imageFrame){
32         abel.frame = imageFrame;
33     };
34 }
35 
36 @end
复制代码

运行效果

 

posted on   低头捡石頭  阅读(17)  评论(0编辑  收藏  举报

编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示