Open benPesso opened 3 years ago
Reproducible on stable channel.
@benPesso can you elaborate why do you want an animation with zero milliseconds
? I can't understand how Flutter can animate without a duration. If you want to switch widgets you can just use a Visibility
widget or similars.
@pedromassangocode You don't necessarily want to set it to zero. As I wrote, it can also happen if the duration is set to something other than zero, like 60 milliseconds. It depends on how fast the code is processed on the given device, I guess. I ran into this issue in one of my projects where I used a 60ms
duration. While researching it, I came across #28434 and decided to make a proper report for it. Hence this post.
One use case is in a preference-based interface; a user might prefer to have a "fast" interface, and the easiest way to achieve that is by setting the duration to zero (or something low, like the above 60ms) when the user switches "Fast Mode" on. Especially if you have the same duration configured globally for multiple widgets.
CC @shihaohong @goderbauer
@dnfield This is a case where the stack trace is truncated (originally brought up in https://github.com/flutter/flutter/issues/52732). I'm not sure how to get more of the stack trace showing, which might help me with figuring out what's wrong here.
I took some time looking at the code, it might be the result of an interaction between the AnimatedSize
and AnimatedCrossFade
's default layout builder, which uses a Stack
. When I modify the code to use a layoutBuilder
using a Column, it no longer happens:
AnimatedCrossFade(
layoutBuilder: (one, oneKey, two, twoKey) {
return Column(
children: [
Container(
key: oneKey,
child: one,
),
Container(
key: twoKey,
child: two,
),
],
);
},
// ....
I'm not exactly sure why this is happening, but since the assertion is happening while attempting to lay out AnimatedSize
, AnimatedCrossFade
may not have the chance to lay out its Stack
before AnimatedSize
wants to lay out.
Running the code sample using latest versions gives below error in the console:
Any progress on this issue? Seems to be stale for quite a while now. 😐
Main issue
As was also reported elsewhere, when using the
AnimatedCrossFade
widget with a duration ofmilliseconds: 0
, Flutter throws an exception:Additionally, documentation in the error itself is severely lacking! It doesn't provide any relevant stack trace, or a thread of information about the offending code line. It is only by trial and error that a developer can figure out that this is caused by an offending
AnimatedCrossFade
widget.Debug Console
``` ════════ Exception caught by animation library ═════════════════════════════════ The following assertion was thrown while notifying listeners for AnimationController: 'package:flutter/src/rendering/object.dart': Failed assertion: line 1530 pos 12: '_debugCanPerformMutations': is not true. Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause. In either case, please report this assertion by filing a bug on GitHub: https://github.com/flutter/flutter/issues/new?template=BUG.md When the exception was thrown, this was the stack #2 RenderObject.markNeedsLayout package:flutter/…/rendering/object.dart:1530 #3 RenderBox.markNeedsLayout package:flutter/…/rendering/box.dart:2147 #4 new RenderAnimatedSize.Sample app
When the widget is first rendered, no exceptions are thrown. It is only once you trigger a cross-fade that the exceptions are thrown on each consecutive call.
One can prevent this exception by increasing the duration, but the amount depends on system resources and complexity of code. For example, in the sample app below, setting the duration to
millisecond: 1
is enough. However, in a more complex app, evenmilliseconds: 60
might not be enough.main.dart
```dart // main.dart import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: HomePage(), ); } } class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends StateFlutter Doctor
Blissfully ignorant, as always. 😐
``` [✓] Flutter (Channel stable, 1.22.4, on macOS 11.0.1 20B29 darwin-x64, locale en-US) • Flutter version 1.22.4 at /Users/benPesso/Projects/flutter • Framework revision 1aafb3a8b9 (12 days ago), 2020-11-13 09:59:28 -0800 • Engine revision 2c956a31c0 • Dart version 2.10.4 [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2) • Android SDK at /Users/benPesso/Library/Android/sdk • Platform android-30, build-tools 30.0.2 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 12.2) • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 12.2, Build version 12B45b • CocoaPods version 1.9.3 [✓] Android Studio (version 4.0) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin version 50.0.1 • Dart plugin version 193.7547 • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593) [✓] VS Code (version 1.51.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.16.0 [✓] Connected device (1 available) • iPhone SE (2nd generation) (mobile) • ED880130-98FA-4356-8F56-B89E9888798E • ios • com.apple.CoreSimulator.SimRuntime.iOS-14-2 (simulator) • No issues found! ```