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
运行效果
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)