mirror of
https://github.com/rive-app/rive-flutter.git
synced 2025-07-04 07:17:59 +08:00
feat!: add audio out-of-band
We'll need to decide on the Enum case for getting the `Type`. Long term it might be better to just not have this to avoid breaking changes. If we decide to remove that, or how it is currently in the PR with the extended conditions, it's a breaking change. The changes to `LocalAssetLoader` aren't breaking though, I realise now. I also removed deprecated things. Diffs= 1a8b3c7cc feat!: add audio out-of-band (#7037) 99d28e1ac Xxxx randomization updates part 2 (#7097) a0004fa72 Xxxx support random transitions (#7094) edac19b06 support randomizing transitions (#7082) Co-authored-by: Gordon <pggordonhayes@gmail.com>
This commit is contained in:
@ -1 +1 @@
|
||||
e64daefffdcd34df6a6cc9f5b54ebc92e0ae89cb
|
||||
1a8b3c7ccd4bb10f085f2b45bf4685cd23cc0b0f
|
||||
|
@ -1,5 +1,8 @@
|
||||
## 0.13.2
|
||||
|
||||
- DEPRECATED: `Extension` and `Type` enum on `FileAsset`. You can create a custom maintained version, see example: https://gist.github.com/HayesGordon/5d37d3fb26f54b2c231760c2c8685963
|
||||
- BREAKING: Removal of previously deprecated methods `assetResolver` on `RiveFile.network` and class `NetworkAssetResolver`
|
||||
- Add Audio out-of-band, with examples.
|
||||
- Support for asset audio volume.
|
||||
- Fixed an issue with audio decoder in web build.
|
||||
- Adds `play()`/`pause()` and `isPlaying` to an `Artboard`. This completely stops the artboard from playing (including nested artboards) and stops/starts the animation ticker. Pausing an artboard can be used to reduce resources used for Rive graphics that aren't visible on screen.
|
||||
|
BIN
example/assets/audio/racket1-59343.wav
Normal file
BIN
example/assets/audio/racket1-59343.wav
Normal file
Binary file not shown.
BIN
example/assets/audio/racket2-59344.wav
Normal file
BIN
example/assets/audio/racket2-59344.wav
Normal file
Binary file not shown.
BIN
example/assets/audio/table-59328.wav
Normal file
BIN
example/assets/audio/table-59328.wav
Normal file
Binary file not shown.
BIN
example/assets/lip-sync.riv
Normal file
BIN
example/assets/lip-sync.riv
Normal file
Binary file not shown.
BIN
example/assets/ping_pong_audio_demo.riv
Normal file
BIN
example/assets/ping_pong_audio_demo.riv
Normal file
Binary file not shown.
@ -12,6 +12,8 @@ import 'package:rive_example/liquid_download.dart';
|
||||
import 'package:rive_example/little_machine.dart';
|
||||
import 'package:rive_example/play_one_shot_animation.dart';
|
||||
import 'package:rive_example/play_pause_animation.dart';
|
||||
import 'package:rive_example/rive_audio.dart';
|
||||
import 'package:rive_example/rive_audio_out_of_band.dart';
|
||||
import 'package:rive_example/simple_animation.dart';
|
||||
import 'package:rive_example/simple_animation_network.dart';
|
||||
import 'package:rive_example/simple_machine_listener.dart';
|
||||
@ -43,7 +45,7 @@ class RiveExampleApp extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _RiveExampleAppState extends State<RiveExampleApp> {
|
||||
// Example animations
|
||||
// Examples
|
||||
final _pages = [
|
||||
const _Page('Simple Animation - Asset', SimpleAssetAnimation()),
|
||||
const _Page('Simple Animation - Network', SimpleNetworkAnimation()),
|
||||
@ -64,6 +66,8 @@ class _RiveExampleAppState extends State<RiveExampleApp> {
|
||||
const _Page('Event Open URL Button', EventOpenUrlButton()),
|
||||
const _Page('Event Sounds', EventSounds()),
|
||||
const _Page('Event Star Rating', EventStarRating()),
|
||||
const _Page('Rive Audio', RiveAudioExample()),
|
||||
const _Page('Rive Audio [Out-of-Band]', RiveAudioOutOfBandExample()),
|
||||
];
|
||||
|
||||
@override
|
||||
|
20
example/lib/rive_audio.dart
Normal file
20
example/lib/rive_audio.dart
Normal file
@ -0,0 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
|
||||
class RiveAudioExample extends StatelessWidget {
|
||||
const RiveAudioExample({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Rive Audio'),
|
||||
),
|
||||
body: const RiveAnimation.asset(
|
||||
"assets/lip-sync.riv",
|
||||
artboard: 'Lip_sync_2',
|
||||
stateMachines: ['State Machine 1'],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
48
example/lib/rive_audio_out_of_band.dart
Normal file
48
example/lib/rive_audio_out_of_band.dart
Normal file
@ -0,0 +1,48 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
|
||||
class RiveAudioOutOfBandExample extends StatefulWidget {
|
||||
const RiveAudioOutOfBandExample({super.key});
|
||||
|
||||
@override
|
||||
State<RiveAudioOutOfBandExample> createState() =>
|
||||
_RiveAudioOutOfBandExampleState();
|
||||
}
|
||||
|
||||
class _RiveAudioOutOfBandExampleState extends State<RiveAudioOutOfBandExample> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadRiveFile();
|
||||
}
|
||||
|
||||
RiveFile? _riveAudioAssetFile;
|
||||
|
||||
Future<void> _loadRiveFile() async {
|
||||
final riveFile = await RiveFile.asset(
|
||||
'assets/ping_pong_audio_demo.riv',
|
||||
assetLoader: LocalAssetLoader(audioPath: 'assets/audio'),
|
||||
);
|
||||
setState(() {
|
||||
_riveAudioAssetFile = riveFile;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_riveAudioAssetFile == null) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Rive Audio [Out-of-Band]'),
|
||||
),
|
||||
body: RiveAnimation.direct(
|
||||
_riveAudioAssetFile!,
|
||||
stateMachines: const ['State Machine 1'],
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
name: rive_example
|
||||
description: A collection of Rive Flutter examples
|
||||
|
||||
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
sdk: ">=2.17.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
@ -28,3 +28,4 @@ flutter:
|
||||
assets:
|
||||
- assets/
|
||||
- assets/fonts/
|
||||
- assets/audio/
|
||||
|
@ -12,6 +12,7 @@ export 'package:rive/src/rive_core/animation/linear_animation_instance.dart';
|
||||
export 'package:rive/src/rive_core/animation/loop.dart';
|
||||
export 'package:rive/src/rive_core/animation/state_machine.dart';
|
||||
export 'package:rive/src/rive_core/artboard.dart';
|
||||
export 'package:rive/src/rive_core/assets/audio_asset.dart';
|
||||
export 'package:rive/src/rive_core/assets/font_asset.dart';
|
||||
export 'package:rive/src/rive_core/assets/image_asset.dart';
|
||||
export 'package:rive/src/rive_core/event.dart';
|
||||
|
@ -2,10 +2,27 @@ import 'package:rive/src/rive_core/assets/file_asset.dart';
|
||||
|
||||
export 'package:rive/src/generated/artboard_base.dart';
|
||||
|
||||
/// TODO: do we prefer this, or do we want to wrap our FileAssets
|
||||
/// into a custom asset class.
|
||||
const _deprecationExtensionMessage =
|
||||
'''This Extension is no longer maintained. Similar behaviour can
|
||||
be re-created with a custom extension.
|
||||
|
||||
Example: https://gist.github.com/HayesGordon/5d37d3fb26f54b2c231760c2c8685963
|
||||
|
||||
''';
|
||||
|
||||
const _deprecationEnumMessage =
|
||||
'''This Enum is no longer maintained. Similar behaviour can
|
||||
be re-created with a custom Enum.
|
||||
|
||||
Example: https://gist.github.com/HayesGordon/5d37d3fb26f54b2c231760c2c8685963
|
||||
|
||||
''';
|
||||
|
||||
@Deprecated(_deprecationExtensionMessage)
|
||||
extension FileAssetExtension on FileAsset {
|
||||
@Deprecated(_deprecationExtensionMessage)
|
||||
Extension get extension => _getExtension(fileExtension);
|
||||
@Deprecated(_deprecationExtensionMessage)
|
||||
Type get type => _getType(fileExtension);
|
||||
}
|
||||
|
||||
@ -38,6 +55,7 @@ Type _getType(String ext) {
|
||||
return Type.unknown;
|
||||
}
|
||||
|
||||
@Deprecated(_deprecationEnumMessage)
|
||||
enum Extension {
|
||||
otf,
|
||||
ttf,
|
||||
@ -47,6 +65,7 @@ enum Extension {
|
||||
unknown,
|
||||
}
|
||||
|
||||
@Deprecated(_deprecationEnumMessage)
|
||||
enum Type {
|
||||
font,
|
||||
image,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:rive/src/asset.dart';
|
||||
import 'package:rive/rive.dart';
|
||||
import 'package:rive/src/debug.dart';
|
||||
import 'package:rive/src/rive_core/assets/file_asset.dart';
|
||||
import 'package:rive/src/utilities/utilities.dart';
|
||||
@ -68,17 +68,37 @@ class CDNAssetLoader extends FileAssetLoader {
|
||||
|
||||
/// Convenience class for loading assets from the local file system.
|
||||
///
|
||||
/// Specify the [fontPath] and [imagePath] to load assets from the asset bundle.
|
||||
/// Specify the [fontPath], [imagePath], and [audioPath] to load assets from the
|
||||
/// asset bundle for a specific asset type. Or use [path] as a general
|
||||
/// fallback instead. [path] will only be used for an asset type if the
|
||||
/// corresponding asset path is null.
|
||||
///
|
||||
/// For example, to provide an audio asset path:
|
||||
/// ```dart
|
||||
/// final riveFile = await RiveFile.asset(
|
||||
/// 'assets/ping_pong_audio_demo.riv',
|
||||
/// assetLoader: LocalAssetLoader(
|
||||
/// audioPath: 'assets/some/path',
|
||||
/// // path: 'assets/some/path', // or provide fallback/general
|
||||
/// ),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// Be sure to provide the correct path where the file is located.
|
||||
///
|
||||
/// If more control is desired, extend [FileAssetLoader] and override [load].
|
||||
class LocalAssetLoader extends FileAssetLoader {
|
||||
final String fontPath;
|
||||
final String imagePath;
|
||||
final String? audioPath;
|
||||
final String? fontPath;
|
||||
final String? imagePath;
|
||||
final String? path;
|
||||
final AssetBundle _assetBundle;
|
||||
|
||||
LocalAssetLoader({
|
||||
required this.fontPath,
|
||||
required this.imagePath,
|
||||
this.audioPath,
|
||||
this.fontPath,
|
||||
this.imagePath,
|
||||
this.path,
|
||||
AssetBundle? assetBundle,
|
||||
}) : _assetBundle = assetBundle ?? rootBundle;
|
||||
|
||||
@ -89,17 +109,35 @@ class LocalAssetLoader extends FileAssetLoader {
|
||||
return false;
|
||||
}
|
||||
String? assetPath;
|
||||
switch (asset.type) {
|
||||
case Type.unknown:
|
||||
|
||||
String filePath;
|
||||
|
||||
switch (asset.runtimeType) {
|
||||
case AudioAsset:
|
||||
assert(audioPath != null || path != null,
|
||||
'''Audio asset not found. Be sure to provide either `audioPath` or `path` in `LocalAssetLoader`.''');
|
||||
if (audioPath == null && path == null) return false;
|
||||
filePath = audioPath ?? path!;
|
||||
break;
|
||||
case FontAsset:
|
||||
assert(fontPath != null || path != null,
|
||||
'''Font asset not found. Be sure to provide either `fontPath` or `path` in `LocalAssetLoader`.''');
|
||||
if (fontPath == null && path == null) return false;
|
||||
filePath = fontPath ?? path!;
|
||||
break;
|
||||
case ImageAsset:
|
||||
assert(imagePath != null || path != null,
|
||||
'''Image asset not found. Be sure to provide either `imagePath` or `path` in `LocalAssetLoader`.''');
|
||||
if (imagePath == null && path == null) return false;
|
||||
filePath = imagePath ?? path!;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
case Type.image:
|
||||
assetPath = imagePath + asset.uniqueFilename;
|
||||
break;
|
||||
case Type.font:
|
||||
assetPath = fontPath + asset.uniqueFilename;
|
||||
break;
|
||||
}
|
||||
|
||||
filePath = filePath.endsWith("/") ? filePath : "$filePath/";
|
||||
|
||||
assetPath = filePath + asset.uniqueFilename;
|
||||
final bytes = await _assetBundle.load(assetPath);
|
||||
await asset.decode(Uint8List.view(bytes.buffer));
|
||||
return true;
|
||||
|
@ -4,12 +4,6 @@ import 'package:rive/src/debug.dart';
|
||||
import 'package:rive/src/rive_core/assets/file_asset.dart';
|
||||
import 'package:rive/src/rive_core/assets/file_asset_contents.dart';
|
||||
|
||||
// TODO: Deprecated. Remove this in the next major version (0.12.0).
|
||||
// ignore: one_member_abstracts
|
||||
abstract class FileAssetResolver {
|
||||
Future<Uint8List> loadContents(FileAsset asset);
|
||||
}
|
||||
|
||||
class FileAssetImporter extends ImportStackObject {
|
||||
final FileAssetLoader? assetLoader;
|
||||
final FileAsset fileAsset;
|
||||
|
@ -339,7 +339,6 @@ class RiveFile {
|
||||
/// [RiveUnsupportedVersionException] if the version is not supported.
|
||||
factory RiveFile.import(
|
||||
ByteData bytes, {
|
||||
@Deprecated('Use `assetLoader` instead.') FileAssetResolver? assetResolver,
|
||||
FileAssetLoader? assetLoader,
|
||||
ObjectGenerator? objectGenerator,
|
||||
bool loadCdnAssets = true,
|
||||
@ -428,7 +427,6 @@ class RiveFile {
|
||||
static Future<RiveFile> network(
|
||||
String url, {
|
||||
Map<String, String>? headers,
|
||||
@Deprecated('Use `assetLoader` instead.') FileAssetResolver? assetResolver,
|
||||
FileAssetLoader? assetLoader,
|
||||
bool loadCdnAssets = true,
|
||||
ObjectGenerator? objectGenerator,
|
||||
@ -475,18 +473,3 @@ class RiveFile {
|
||||
Artboard? artboardByName(String name) =>
|
||||
_artboards.firstWhereOrNull((a) => a.name == name);
|
||||
}
|
||||
|
||||
// TODO: remove in v0.13.0
|
||||
|
||||
/// Resolves a Rive asset from the network provided a [baseUrl].
|
||||
@Deprecated('Use `CallbackAssetLoader` instead. Will be removed in v0.13.0')
|
||||
class NetworkAssetResolver extends FileAssetResolver {
|
||||
final String baseUrl;
|
||||
NetworkAssetResolver(this.baseUrl);
|
||||
|
||||
@override
|
||||
Future<Uint8List> loadContents(FileAsset asset) async {
|
||||
final res = await http.get(Uri.parse(baseUrl + asset.uniqueFilename));
|
||||
return Uint8List.view(res.bodyBytes.buffer);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user