跳到主要内容

加载资源

概览

Rive 资源(如图像、字体和音频)可以通过多种方式加载。本指南介绍如何在运行时动态加载和替换资源。

资源加载方法

Rive 支持三种类型的资源:

  • 嵌入式资源:直接编码在 .riv 文件中
  • 引用资源:在编辑器中标记为"引用",需要在运行时由应用提供
  • CDN 资源:托管在 Rive CDN 上,由运行时自动加载

嵌入式资源

嵌入式资源直接包含在 Rive 文件中,无需额外处理即可使用。

CDN 图像

CDN 托管的资源可以自动加载,也可以通过自定义逻辑处理。

引用资源

引用资源在编辑器中标记为单独加载,需要应用在运行时提供实际的资源数据。

处理资源

当前运行时

本节假设你已阅读了 Apple 概述。

引用资源可以使用 Worker 的全局资源 API 添加。

添加全局资源是一个两步过程:

  1. 从字节解码资源
  2. 将资源添加到 worker

全局资源是推送式的,这意味着你必须提前知道资源的唯一名称。你可以从包含资源的导出 .zip 文件中检索资源的唯一名称。唯一标识符是附加到资源名称的标识符(例如 Font-1234)。

无需维护对资源的强引用。当 worker 被释放时,资源将自动清理。

// 字体
let worker = try await Worker()
let fontData: Data = ...
let font = try await worker.decodeFont(from: fontData)
worker.addGlobalFontAsset(font, name: "MyFont-1234")

// 如果你想清理资源
worker.removeGlobalFontAsset(name: "MyFont-1234")
// 音频
let worker = try await Worker()
let audioData: Data = ...
let audio = try await worker.decodeAudio(from: audioData)
worker.addGlobalAudioAsset(audio, name: "MyAudio-1234")

// 如果你想清理资源
worker.removeGlobalAudioAsset(name: "MyAudio-1234")
// 图像
let worker = try await Worker()
let imageData: Data = ...
let image = try await worker.decodeImage(from: imageData)
worker.addGlobalImageAsset(image, name: "MyImage-1234")

// 如果你想清理资源
worker.removeGlobalImageAsset(name: "MyImage-1234")

旧版运行时

示例

使用资源处理器 API

实例化 RiveViewModel(或直接使用 RiveFile)时,将 customLoader 回调属性添加到参数列表中。此回调将在运行时从 .riv 文件加载时检测到的每个资源被调用,回调将负责处理运行时资源的加载,或者传递责任让运行时尝试加载。

你可能需要处理资源加载的一个场景是,如果文件中的资源标记为引用,你需要提供实际的资源来渲染图形,因为 Rive 没有将其嵌入 .riv 中,因此无法加载。

你可能希望让运行时尝试加载资源的一个场景是,如果文件中的资源标记为托管,你希望将加载责任传递给运行时(运行时将调用 Rive CDN 进行加载)。

RiveViewModel(fileName: "simple_assets", loadCdn: false, customLoader: { (asset: RiveFileAsset, data: Data, factory: RiveFactory) -> Bool in
// 对只有一个资源的 Rive 文件进行简单检查
if (asset is RiveImageAsset){
// picture-47982.jpeg 可以从 Rive 编辑器与 .riv 文件一起导出。
// 然后将其包含在项目的主 bundle 资源中
guard let url = (.main as Bundle).url(forResource: "picture-47982", withExtension: "jpeg") else {
fatalError("Failed to locate 'picture-47982' in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(url) from bundle.")
}
(asset as! RiveImageAsset).renderImage(
factory.decodeImage(data)
)
return true;
}
return false;
}).view()

你提供的回调将收到 assetdatafactory

  • asset - 对 RiveFileAsset 对象的引用。你将使用此引用为动态加载的内容设置新的 Rive 特定资源。如果你希望在视图的生命周期内动态替换给定的图像/字体,你可能需要缓存此对象。你可以从此对象获取多个属性,例如:

    • name() - 不带唯一文件标识符的资源名称(即 picture.webp 而非 picture-47982.webp
    • uniqueFilename() - 带唯一文件标识符的资源名称(即 picture-47982.webp 而非 picture.webp
    • fileExtension() - 文件扩展名(即 "png"
    • cdnBaseUrl() - CDN 的基础 URL 名称
    • cdnUuid() - Rive CDN 中资源的标识符。可用于查看是否有长度,以确定资源是否标记为从 Rive CDN 获取(在这种情况下,你可以让 Rive 运行时检索资源,而不是你的应用逻辑)
  • data - 资源的字节数组。这有助于确定资源是否已嵌入 Rive 文件中(即在编辑器中未标记为"引用")

  • factory - 具有将资源字节转换为 RiveRenderImageRiveFontRiveAudio 方法的工具,asset 对象通过 .renderImage(your-rive-render-image).font(your-rive-font).audio(your-rive-audio) 使用这些方法进行渲染。这些资源通过调用 factory.decodeImage(data)factory.decodeFont(data)factory.decodeAudio(data) 来创建

重要提示:请注意回调的返回值是 boolean,你需要返回:

  • true 如果你打算自己处理和加载资源,或
  • false 如果你不想自己处理该资源的加载,并尝试让运行时加载该资源。

示例用法

import SwiftUI
import RiveRuntime

struct SimpleAssetReplacement: View {
@StateObject private var riveInstance = RiveViewModel(fileName: "simple_assets", autoPlay: false, loadCdn: false, customLoader: { (asset: RiveFileAsset, data: Data, factory: RiveFactory) -> Bool in
if (asset is RiveImageAsset) {
guard let url = (.main as Bundle).url(forResource: "picture-47982", withExtension: "jpeg") else {
fatalError("Failed to locate 'picture-47982' in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(url) from bundle.")
}
(asset as! RiveImageAsset).renderImage(
factory.decodeImage(data)
)
return true;
} else if (asset is RiveFontAsset) {
guard let url = (.main as Bundle).url(forResource: "Inter-45562", withExtension: "ttf") else {
fatalError("Failed to locate 'Inter-45562' in bundle.")
}
guard let data = try? Data(contentsOf: url) else {
fatalError("Failed to load \(url) from bundle.")
}
(asset as! RiveFontAsset).font(
factory.decodeFont(data)
)
return true;
}
return false;
})

var body: some View {
riveInstance.view()
}
}

字体

使用自定义加载器时,引用字体可以通过两种方式加载:使用原始数据(来自文件,如上所示),或使用 UIFont / NSFont。 使用 UIFont / NSFont 时,提供的字体的尺寸、粗细和宽度将被忽略。字体将按文本运行中定义的方式使用,而不是被提供的字体的样式覆盖。

import SwiftUI
import RiveRuntime

struct SimpleFontReplacement: View {
@StateObject private var riveInstance = RiveViewModel(fileName: "simple_assets", autoPlay: false, loadCdn: false, customLoader: { (asset: RiveFileAsset, data: Data, factory: RiveFactory) -> Bool in
if (asset is RiveFontAsset) {
(asset as! RiveFontAsset).font(
factory.decodeFont(UIFont.systemFont(ofSize: 12))
)
return true;
}
return false;
})

var body: some View {
riveInstance.view()
}
}

图像

加载引用图像的资源时,你可能需要将本地资源缩放到 Rive 文件中定义的图像资源大小。使用自定义加载器时,你可以通过 RiveImageAssetsize 属性访问引用图像的大小。

import SwiftUI
import RiveRuntime

struct SimpleImageSizeReplacement: View {
@StateObject private var riveInstance = RiveViewModel(fileName: "simple_assets", autoPlay: false, loadCdn: false, customLoader: { (asset: RiveFileAsset, data: Data, factory: RiveFactory) -> Bool in
guard let imageAsset = asset as? RiveImageAsset else { return false }
let requestedSize = imageAsset.size
let image = UIImage(...)
let resizedImage = resize(image, to: requestedSize)
guard let pngData = resizedImage.pngData() else { return false }
imageAsset.renderImage(
factory.decodeImage(pngData)
)
return true
}
return false;
}

var body: some View {
riveInstance.view()
}
}

资源