From 0c3d4bdf848ea2ed8967ea01ad0e79417e6ab7ee Mon Sep 17 00:00:00 2001 From: HayesGordon Date: Fri, 19 Jul 2024 11:40:48 +0000 Subject: [PATCH] fix: always advance Fixes https://github.com/rive-app/rive-flutter/issues/408 and https://github.com/rive-app/rive-flutter/issues/409 I left some notes in the code for future consideration, @luigi-rosso. This is the least intrusive change that will not break golden tests (for us and users). Diffs= fd6aa55ed fix: always advance (#7615) 49cabe3cb update data bind mode to flags (#7612) 6c5c79b75 Only set Core Audio session category for iOS targets (#7624) 8e1be1223 Run tests, bench, gms, & goldens on a physical Pixel 8 on CI (#7618) 238bf2fe1 Set audio to mix on for iOS (simulator) and Catalyst (#7555) ca56d7565 Vulkan! (#7553) 63b6a13d3 Use "python3" in make_viewer_skia.sh (instead of "python") (#7597) 8a67331a4 Fix build on web. (#7613) 44fae6bfe explicit linux arch (#7606) 2a1db3835 handle linux warnings (#7598) c5eb69645 add pic (#7589) 3bf0df5c0 Fixing windows build with rive_native. (#7575) Co-authored-by: Gordon --- .rive_head | 2 +- CHANGELOG.md | 9 +++++++++ lib/src/rive_render_box.dart | 38 +++++++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/.rive_head b/.rive_head index 7510dfe..d847686 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -a0a6c0d3bd385f32dd51e1fbcb75306332b9d1cc +fd6aa55ed53ab88fcc9ece52bc6cc7bb2680f5de diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d21fda..b6f821d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,28 @@ +## Upcoming + +- Fix [408](https://github.com/rive-app/rive-flutter/issues/408) and [409](https://github.com/rive-app/rive-flutter/issues/409), Rive never reaching a settled state when the widget is not visible (paint method not called). + ## 0.13.9 + - Preperation for data binding ([databinding](https://github.com/rive-app/rive-flutter/commit/6ceb7a544e7124d303259f7d032641e5b38f7fc1), [data binding data context](https://github.com/rive-app/rive-flutter/commit/6d002300a6f0fd19f6dacac58a499ccc903a214d), [databinding add boolean](https://github.com/rive-app/rive-flutter/commit/90b8c81f0e496502b70db4d550341f5acabbbea6)). - Layout fixes and improvements ([animations for layouts](https://github.com/rive-app/rive-flutter/commit/8068e48eb2faa2a13eab1ba858b4e0737cf0265b), [layout UX fixes](https://github.com/rive-app/rive-flutter/commit/21bd3765ddc3ef8c3b1f0199f75eae21434cf52b)). - Android example project [fix](https://github.com/rive-app/rive-flutter/commit/9951f912df4c6f0574f57d5a152cd36e6ad2d7e0). ## 0.13.8 + - Add `key` property to `Rive` widget. - Nested linear animations report events up to parent artboards. Previously, only nested state machines could report events so that listeners in parent artboards could listen for them. ## 0.13.7 + - Add `getComponentWhereOrNull` on `Artboard`, to find a component that matches the given predicate. This can be used instead of `forEachComponent` as it allows exiting early. ## 0.13.6 + - Add `getBoolInput(name, path)`, `getTriggerInput(name, path)`, and `getNumberInput(name, path` on `Artboard` to set nested inputs (inputs on nested artboards), see [the documentation](https://rive.app/community/doc/state-machines/docxeznG7iiK#nested-inputs). ## 0.13.5 + - Migrates to `dart:js_interop` and `package:web` APIs. - DEPRECATED: `RiveFile.initializeText` - use `RiveFile.initialize` instead. This now initializes the Rive audio, text, and layout engine. Call `await RiveFile.initialize()` before doing `RiveFile.import`. `RiveFile.asset`, `RiveFile.network`, and `RiveFile.file` will call initialize automatically if it has not been initialized. Alternatively, you can also call `unawaited(RiveFile.initialize());` in the `main` method on app start to make the first graphic load faster. diff --git a/lib/src/rive_render_box.dart b/lib/src/rive_render_box.dart index 45e523e..a540af7 100644 --- a/lib/src/rive_render_box.dart +++ b/lib/src/rive_render_box.dart @@ -89,6 +89,8 @@ abstract class RiveRenderBox extends RenderBox { } } + bool _paintedLastFrame = false; + @override bool get sizedByParent => !useArtboardSize; @@ -257,8 +259,33 @@ abstract class RiveRenderBox extends RenderBox { } void _frameCallback(Duration duration) { + // Under certain conditions Flutter will not call paint (for optimization). + // If the animation did not paint in the last frame, we force + // advance so that the animation can reach a settled state. + + // TODO: Ideally "advance" should only happen inside_`_frameCallback` + // and not inside `paint`. But to support backwards compatibility we + // will continue to advance in `paint` (golden tests), and just introduce + // this as a backup to resolve: + // - https://github.com/rive-app/rive-flutter/issues/409 + // - https://github.com/rive-app/rive-flutter/issues/408 + // + // In the next version of the runtime that uses rive_native we can rework + // this logic. + // + // TODO: We also need to consider standard default behaviour for what + // Rive should do when not visible on the screen + // - Advance and not draw + // - Draw and advance + // - Neither advance nor draw + // - (Optional enum for users to choose) + if (!_paintedLastFrame) { + _advanceFrame(); + } + _calculateElapsedSeconds(duration); + _paintedLastFrame = false; markNeedsPaint(); } @@ -349,13 +376,18 @@ abstract class RiveRenderBox extends RenderBox { return transform; } - @protected - @override - void paint(PaintingContext context, Offset offset) { + void _advanceFrame() { if (!advance(_elapsedSeconds)) { _stopTicker(); } _elapsedSeconds = 0; + } + + @protected + @override + void paint(PaintingContext context, Offset offset) { + _paintedLastFrame = true; + _advanceFrame(); if (customPaint(context, offset)) { return;