Rive:是什么,Flutter 和 iOS 的动画工具

作者: IT Sectr 发布日期: 2026-03-01 阅读时间: 11 分钟

Rive — 一个用于创建和播放交互式矢量动画的工具,它结合了动画编辑器和移动平台的运行时库。与被动格式不同,Rive 支持状态机 — 根据用户操作在动画之间切换的逻辑。根据 Rive 博客(2026 年),该工具已用于超过 10,000 个项目,包括 Duolingo 和 Bumble。有关其他动画类型的更多信息,请阅读通用动画指南

要点

  • Rive — 具有自己编辑器的交互式矢量动画工具。
  • 状态机 — 通过触发器在动画之间切换的可视化逻辑。
  • RiveRuntime — 适用于 iOS、Android、Flutter 和 Web 的播放库。
  • RiveAnimation — 用于 Flutter 的 Dart 组件,用于将 .riv 文件嵌入到应用程序中。
  • .riv 格式 — 包含动画和状态机的二进制容器。

什么是 Rive?

Rive(前身为 Rive.app,成立于 2016 年)— 是一个用于交互式矢量动画的图形编辑器和跨平台运行时。与 After Effects + Bodymovin(Lottie)不同,Rive 提供统一的环境:设计师直接在编辑器中绘制、动画和配置切换逻辑。结果导出为 .riv 二进制文件,大小根据复杂性为 2 到 50 KB。

Rive 与其他解决方案的主要区别 — 状态机。这是一个可视化图形,其中节点是动画(空闲、悬停、按下、激活),它们之间的切换由触发器(触摸、拖动、布尔值)激活。开发者在代码中只需发送触发器,RiveRuntime 自行决定播放哪个动画以及如何平滑切换。根据 Rive Engineering(2026 年),带有状态机的平均 .riv 动画占用 15 KB — 比等效视频文件小 5–10 倍。

Rive 运行时适用于 Flutter、iOS(Swift)、Android(Kotlin/Java)、Web(WASM)和 React。渲染通过 Skia(Flutter/Web)、Core Graphics(iOS)或 Canvas(Android)完成。Rive 支持形状动画(旋钮、滑块、具有自定义几何形状的按钮),从而可以创建完全动画化的 UI 组件,而不仅仅是装饰性动画。

Rive 与 Lottie:方法比较

Rive 和 Lottie 解决不同的任务。Lottie 是 After Effects 成品动画的播放器,最适合被动装饰效果。Rive 是创建具有自己逻辑的交互式动画的工具,其中动画对用户操作做出反应。选择取决于所需的交互程度。

标准RiveLottie
编辑器自有(Rive 编辑器)Adobe After Effects + Bodymovin
交互性状态机、触发器、布尔值、数字仅播放/暂停/搜索
格式.riv(二进制).json 或 .lottie(protobuf)
渲染Skia / Core Graphics / CanvasCanvas / Core Animation / Skia
动画 UI旋钮、滑块、按钮、输入(内置)无(仅装饰层)

何时选择 Rive:具有点击响应的交互式按钮、游戏元素(具有状态的角色)、带动画的开关、响应状态的动态图标。何时选择 Lottie:预加载器、点赞、欢迎屏幕、无逻辑的重音动画。对于 Flutter 项目,由于与 Skia 和 Flutter 渲染管线的原生集成,Rive 是首选。

在 Flutter 中集成 Rive(Dart)

在 Flutter 中,RiveAnimation 是嵌入 .riv 文件的主要组件。它通过 rive 包(官方)提供。RiveAnimation 支持参数:artboard(选择画板)、animation(动画名称)、fit、alignment、controllers(用于状态机)。对于交互式场景,使用 StateMachineController。

dart
import 'package:rive/rive.dart';

// 简单动画播放
RiveAnimation.asset(
  'assets/animations/button.riv',
  artboard: 'Button',
  animations: const ['idle'],
  fit: BoxFit.contain,
)

// 带触发器的 StateMachineController
class InteractiveButton extends StatefulWidget {
  @override
  State<InteractiveButton> createState() => _InteractiveButtonState();
}

class _InteractiveButtonState extends State<InteractiveButton> {
  StateMachineController? _controller;
  SMIInput<bool>? _isPressed;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTapDown: (_) => _isPressed?.value = true,
      onTapUp: (_) => _isPressed?.value = false,
      child: RiveAnimation.asset(
        'assets/animations/button.riv',
        fit: BoxFit.contain,
        onInit: (artboard) {
          _controller = StateMachineController.fromArtboard(
            artboard, 'State Machine 1',
          );
          if (_controller != null) {
            artboard.addController(_controller!);
            _isPressed = _controller!.findInput<bool>('isPressed');
          }
        },
      ),
    );
  }
}

Flutter 最佳实践:通过 RiveAnimation.asset(内置 AssetBundle)异步加载 .riv 文件。对于列表视图,使用在元素之间共享的一个 StateMachineController。Rive 不再需要单独的导入 — rive v0.12+ 包含所有功能。对于自定义动画,直接控制 RiveAnimationController — 它提供对动画、混合和速度的访问。

在 iOS 中集成 Rive(Swift)

在 iOS 中,RiveRuntime 由 RiveView(UIKit)和 RiveViewModel(SwiftUI)类表示。库通过 Swift Package Manager 连接。RiveView 通过 Core Graphics 和 Metal 渲染 .riv 文件,在 ProMotion 显示屏上支持 120 FPS。对于状态机,使用 RiveStateMachineLayer 绑定到触发器。

swift
import RiveRuntime

// SwiftUI:带动画的 RiveViewModel
struct RiveAnimationView: View {
    @State private var isPressed = false

    var body: some View {
        RiveViewModel(fileName: "button").view()
            .frame(width: 200, height: 60)
            .gesture(
                DragGesture(minimumDistance: 0)
                    .onChanged { _ in
                        if !isPressed {
                            isPressed = true
                            // 通过状态机的触发器
                        }
                    }
                    .onEnded { _ in
                        isPressed = false
                    }
            )
    }
}

// UIKit:手动控制的 RiveView
let riveView = RiveView()
riveView.configure(fileName: "loading", extension: "riv")
riveView.fit = .contain
riveView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(riveView)

// 状态机管理
riveView.triggerInput(named: "startAnimation")

iOS 最佳实践:对于 SwiftUI 使用 RiveViewModel — 它自动管理生命周期。对于 UIKit,订阅 RiveViewDelegate 以跟踪事件。由于通过 Core Graphics 渲染,Rive 在 iOS 上比 Lottie 消耗更少的 CPU。对于 NavigationView/UICollectionView 中的动画,通过 RiveFile.preload() 使用预取。

在 Android 中集成 Rive(Kotlin)

在 Android 中,RiveAnimationView 是嵌入 .riv 动画的主要视图。库 app.rive:rive-android 通过 Gradle 连接。RiveAnimationView 继承自 View 并通过 Canvas 渲染,支持硬件加速。状态机通过 setTriggers 和 setInputs 管理。

kotlin
// build.gradle.kts
implementation("app.rive:rive-android:0.9.0")

// XML layout
<app.rive.RiveAnimationView
    android:id="@+id/riveView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:rive_file="@raw/mascot"
    app:rive_artboard="Mascot"
    app:rive_animation="idle" />

// Kotlin:状态机管理
import app.rive.riveandroid.RiveAnimationView
import app.rive.riveandroid.StateMachineInput

val riveView = findViewById<RiveAnimationView>(R.id.riveView)
riveView.post {
    riveView.setTriggers("hover") "> 向 State Machine 发送触发器
    riveView.setInput("speed", 1.5f)
    riveView.setInput("isActive", true)
    riveView.play()
}

// 动画完成处理
riveView.addListener(object : RiveAnimationView.RiveListener() {
    override fun onAnimationCompleted(animationName: String) {
        Log.d("Rive", "Animation $animationName completed")
    }
})

Android 最佳实践:通过 res/raw(内置资源)或 assets(网络加载)加载 .riv 文件。RiveAnimationView 自动处理生命周期 — 不要在 onResume/onPause 中手动调用 play/pause。对于 RecyclerView 中的动画,使用 setOnScrollListener 在滚动时暂停播放。根据 Rive 文档(2026 年),高达 100 KB 的 .riv 文件在中端设备上可在 5–10 毫秒内解析。

状态机:Rive 中的切换逻辑

状态机 — Rive 的关键功能,使其区别于被动动画格式。这是一个可视化图形,其中顶点是状态(动画),边是由触发器激活的切换。状态机在 Rive 编辑器中创建:设计师添加动画节点,用线连接它们,并分配触发器(触摸、布尔值、数字)。开发者只需从代码中发送这些触发器。

dart
// Flutter:完全控制状态机
import 'package:rive/rive.dart';

class RiveStateMachineWidget extends StatefulWidget {
  @override
  State<RiveStateMachineWidget> createState() => _RiveStateMachineWidgetState();
}

class _RiveStateMachineWidgetState extends State<RiveStateMachineWidget> {
  Artboard? _artboard;
  StateMachineController? _controller;
  SMIInput<bool>? _isHovered;
  SMIInput<double>? _progress;

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      onEnter: (_) => _isHovered?.value = true,
      onExit: (_) => _isHovered?.value = false,
      child: RiveAnimation.asset(
        'assets/interactive_icon.riv',
        onInit: (artboard) {
          _controller = StateMachineController.fromArtboard(
            artboard, 'State Machine 1',
          );
          artboard.addController(_controller!);
          _isHovered = _controller!.findInput<bool>('isHovered');
          _progress = _controller!.findInput<double>('progress');
        },
      ),
    );
  }
}

// 发送数值
SMIInput<double> speedInput = controller.findInput('speed');
speedInput?.value = scrollPosition;

触发器类型:布尔值 — 开关(true/false),数字 — 数值(0.0–1.0 或任意范围),触发器 — 一次性脉冲(按钮按下)。在 Rive 编辑器中可以配置切换平滑度(过渡持续时间) — 建议值为 100–300 毫秒以获得平滑效果。对于复杂的 UI 状态,使用嵌套状态机 — 动画的每个部分都独立管理。Rive 状态机在所有平台上无需更改 .riv 文件即可工作 — 切换逻辑嵌入在文件中,而不是应用程序代码中。

常见问题

Rive 与 Lottie 有何不同?

Rive — 具有状态机、触发器和自有编辑器的交互式动画。Lottie — 来自 After Effects 的 JSON 动画的被动播放。Rive 适用于按钮、游戏和具有用户响应的 UI 元素。Lottie — 用于装饰效果(预加载器、点赞)。Rive 使用 .riv 格式,Lottie 使用 JSON 或 .lottie 格式。

可以在没有状态机的情况下使用 Rive 吗?

可以。Rive 支持没有状态机的简单动画播放 — 在 RiveAnimation.asset 或 RiveView 中指定 animationName。在这种情况下,Rive 像 Lottie 一样工作:循环或一次性动画。状态机是用于交互性的可选层。对于只需要装饰性动画的项目,状态机是多余的。

Rive 与 Android Jetpack Compose 兼容吗?

是的,通过 AndroidView 将 RiveAnimationView 嵌入到 Compose 中。从 rive-android 0.9.0 开始,提供了支持修饰符的 Compose 封装 RiveAnimation compose()。对于状态机管理,使用 remember { StateMachineHolder() }。Rive 还通过共享的 Compose 运行时在 iOS 上支持 Compose Multiplatform。

Rive 在 Flutter Web 上工作吗?

是的,Rive 通过 Skia Wasm(CanvasKit)或 HTML 渲染器支持 Flutter Web。建议使用 CanvasKit 以获得最大性能。Rive 文件通过 HTTP 请求(RiveAnimation.network)加载或打包在 assets 中。带有 Rive 的 Flutter Web 在所有现代浏览器(Chrome 90+、Safari 15+、Firefox 90+)中都能正常工作。

如何在移动设备上优化 Rive 性能?

将同时活动的图层数量限制在 20–30 个。对于简单形状,使用平面着色而不是渐变。对于带文字的动画,使用系统文字(而不是 Rive 编辑器中的矢量文字)。尽量减少角色的骨骼动画数量 — 对于 UI 元素来说不需要。在旧设备上,在 Android 上使用 riveView.enableDoubleBuffering = false 禁用双缓冲。

总结

  • Rive — 具有自己的编辑器和运行时适用于 5 个以上平台的交互式矢量动画。
  • 状态机 — 通过触发器(触摸、布尔值、数字)在动画之间切换的内置逻辑。
  • RiveRuntime — 适用于 Flutter、iOS、Android、Web 和 React 的库,通过 Skia/Core Graphics 渲染。
  • .riv 格式 — 包含动画和状态机的 2–50 KB 二进制容器。
  • RiveAnimation(Flutter)、RiveViewModel(SwiftUI)、RiveAnimationView(Android)— 主要组件。
  • Rive 适用于交互式 UI 元素,Lottie 适用于被动装饰性动画。
  • 触发器类型:布尔值(开关)、数字(数值)、触发器(脉冲)。建议的过渡持续时间 — 100–300 毫秒。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读