iOS视图的Material Design水波纹效果实现(附实现代码)

效果图

实现思路

在开始编写任何代码之前,我们需要决定如何实现这个效果。它会是某个特定UIView的子类吗?还是一种新的UIView类型,可以作为子视图添加?我选择了以上都不是,而是决定使用扩展(Category)来扩展UIView,这是一个简单而有效的方法。通过创建一个新的扩展,我们可以无缝地将这个效果添加到任何UIView中,而不会遇到任何麻烦。

既然我们知道了要在哪里编写代码,我们需要为这个动画定义一个API。目前,这个实现将是简单的。对于动画,我们需要定义几个要素:

  • 作为动画起点的位置。
  • 我们想要的涟漪颜色。
  • 我们希望涟漪有多大。
  • 我们希望它扩展的速度,或者换句话说,我们希望动画持续多长时间。
  • 涟漪何时开始淡出。

在本文的末尾,你可以找到一个包含所有这些代码的存储库链接,但让我们先看看如何构建代码。

我们的UIView类别(Category)将如下所示:

objectivec 复制代码
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

typedef void(^JCNFlashButtonDidClickBlock)(void);

@interface UIView (JCNSimpleRipple)

/// clickCallback
@property (nonatomic, strong) JCNFlashButtonDidClickBlock clickCallback;

///  开始波纹动画
/// - Parameters:
///   - origin: starting point for our animation
///   - color: The color we want our ripple to have.
///   - duration: how long we want our animation to last.
///   - radius: How big we want our ripple to be.
///   - fadeAfter: When the ripple should start fading.
///   - callback: 动画结束后的回调

- (void)rippleStartingAt:(CGPoint)origin
               withColor:(UIColor *)color
                duration:(NSTimeInterval)duration
                  radius:(CGFloat)radius
               fadeAfter:(NSTimeInterval)fadeAfter
            clickCallbck:(JCNFlashButtonDidClickBlock)callback;

@end

NS_ASSUME_NONNULL_END

我们的动画将在一个新的CAShapeLayer中进行。这个新的图层将位于所有其他图层的后面,以确保它不会遮挡UIView的任何内容。然后,我们将添加一个CABasicAnimation来对路径进行变换。这个路径将是实际的涟漪,它将从一个小小的圆形变换为我们在参数中指定的大小。

这是一个简化版的实现方法:

ini 复制代码
    CAShapeLayer *rippleLayer = [CAShapeLayer layer];
    UIBezierPath *startPath = [UIBezierPath bezierPathWithArcCenter:origin
                                                         radius:startRadius
                                                         startAngle:0 endAngle:FULL
                                                         clockwise:YES];

    UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:origin
                                                           radius:endRadius
                                                       startAngle:0 endAngle:FULL
                                                        clockwise:YES];

    CABasicAnimation *rippleAnimation = [CABasicAnimation animationWithKeyPath:@"path"];

    rippleAnimation.fillMode = kCAFillModeBoth;
    rippleAnimation.duration = duration;
    rippleAnimation.fromValue = (id)(startPath.CGPath);
    rippleAnimation.toValue = (id)(endPath.CGPath);
    rippleAnimation.removedOnCompletion = NO;
    rippleAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

    [self.layer insertSublayer:rippleLayer atIndex:0];
    [rippleLayer addAnimation:rippleAnimation forKey:nil];

对于淡出效果,我们将以类似的方式处理:

ini 复制代码
CABasicAnimation *fadeOutAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeOutAnimation.fromValue = @1;
fadeOutAnimation.toValue = @0;
fadeOutAnimation.duration = fadeOutDuration;
fadeOutAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

[rippleLayer addAnimation:fadeOutAnimation forKey:nil];

最后,一旦我们完成动画,我们可以从UIView中移除涟漪动画。但是有一个小问题。通常我们会使用CAAnimationDelegate并实现适当的回调方法,但是我们要么必须存储对新添加图层的引用,要么必须遍历子图层并找到相应的图层。这也意味着我们不能(至少不容易)同时拥有多个涟漪动画。因此,我们将采用非常简单的解决方案,在动画完成时,我们将排队执行一段代码块,并在该代码块中将涟漪图层移除。

objc 复制代码
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC), dispatch_get_main_queue(), ^{

    [rippleLayer removeAllAnimations]; 
    [rippleLayer removeFromSuperlayer];

});

仓库链接: github.com/Yinjianhua4...

相关推荐
qq7422349847 小时前
VitePress静态网站从零搭建到GitHub Pages部署一站式指南和DeepWiki:AI 驱动的下一代代码知识平台
人工智能·python·vue·github·vitepress·wiki
胖虎116 小时前
SwiftUI 页面作为一级页面数据被重置问题分析
ios·swiftui·swift·state·observedobject·stateobject·swiftui页面生命周期
用户219916797039118 小时前
.Net通过EFCore和仓储模式实现统一数据权限管控并且相关权限配置动态生成
后端·github
健了个平_2420 小时前
【iOS】如何在 iOS 26 的UITabBarController中使用自定义TabBar
ios·swift·wwdc
DKNG21 小时前
【Windows Host】 hosts配置增加访问github流畅度
人工智能·git·github
逛逛GitHub1 天前
我把公众号文章导入了腾讯 ima,可以对话找开源项目了。
前端·github
Digitally1 天前
无需 iTunes 将文件从 PC 传输到 iPhone
ios·iphone
徐小夕1 天前
10k Star 的开源 AI 记忆引擎:6 行代码,用图谱+向量打造永不遗忘的 AI
前端·后端·github
1024小神1 天前
xcode 配置了AppIcon 但是不显示icon图标
ios·swiftui·swift
慕容长风1 天前
github使用指南
github