-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Description
A two-part Impeller-specific bug here:
- Regression in the way gradients are rendered
- Jank when animating said gradients
MCVE
Minimal example repo available here: https://github.com/isaaclyman/flutter-impeller-gradient-bug
Steps to Reproduce
To see the first bug, a simple widget like this one will do:
class FlutterImpellerGradientBug extends StatefulWidget {
final color1 = Colors.red;
final color2 = Colors.green;
const FlutterImpellerGradientBug({super.key});
@override
State<FlutterImpellerGradientBug> createState() =>
_FlutterImpellerGradientBugState();
}
class _FlutterImpellerGradientBugState
extends State<FlutterImpellerGradientBug> {
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
height: 100,
width: 100,
child: DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
widget.color1,
widget.color1,
widget.color2,
widget.color2,
],
stops: [
0.0,
0.5,
0.5,
1.0,
],
),
),
),
),
);
}
}This is a (perhaps naive) way of rendering a box with a simple horizontal color split: red on top, green on bottom. With Skia you get the following, which is what you'd expect:
With Impeller enabled, you get this instead:
Things get worse when you try to animate the boundary between the colors. Here's a widget that does exactly that:
class _FlutterImpellerAnimatedGradientBug extends StatefulWidget {
final color1 = Colors.red;
final color2 = Colors.green;
const _FlutterImpellerAnimatedGradientBug();
@override
State<_FlutterImpellerAnimatedGradientBug> createState() =>
_FlutterImpellerAnimatedGradientBugState();
}
class _FlutterImpellerAnimatedGradientBugState
extends State<_FlutterImpellerAnimatedGradientBug>
with TickerProviderStateMixin {
late final AnimationController _animation =
AnimationController(duration: const Duration(seconds: 2), vsync: this);
@override
void initState() {
super.initState();
_animation.repeat(reverse: true);
}
@override
void dispose() {
_animation.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
height: 100,
width: 100,
child: AnimatedBuilder(
animation: _animation,
builder: (context, _) {
final animationProgress =
Tween(begin: 0.0, end: 1.0).evaluate(_animation);
return DecoratedBox(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
widget.color1,
widget.color1,
widget.color2,
widget.color2,
],
stops: [
0.0,
animationProgress,
animationProgress,
1.0,
],
),
),
);
}),
),
);
}
}With Skia, the boundary animates smoothly up and down, as expected.
With Impeller, it's hard to tell what the animation is trying to do. If my TV did this when I was a kid, it meant the antenna needed to be adjusted. :)
Code sample
Logs
GitHub won't let me submit the ticket if I include the full output of flutter run --verbose.
There was an error creating your Issue: body is too long, body is too long (maximum is 65536 characters).
Analyzing flutter_impeller_gradient_bug...
No issues found! (ran in 1.0s)
[✓] Flutter (Channel stable, 3.7.0, on macOS 13.0.1 22A400 darwin-arm64, locale en-US)
• Flutter version 3.7.0 on channel stable at /Users/isaaclyman/code/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision b06b8b2710 (2 days ago), 2023-01-23 16:55:55 -0800
• Engine revision b24591ed32
• Dart version 2.19.0
• DevTools version 2.20.1
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
• Android SDK at /Users/isaaclyman/Library/Android/sdk
• Platform android-33, build-tools 33.0.0
• Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 14C18
• CocoaPods version 1.11.3
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 2021.3)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
[✓] VS Code (version 1.74.3)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.58.0
[✓] VS Code (version 1.71.2)
• VS Code at /Users/isaaclyman/Downloads/Visual Studio Code.app/Contents
• Flutter extension version 3.58.0
[✓] Connected device (3 available)
• iPhone 13 Pro Max (mobile) • 9AAEC81E-3ECD-4455-BD0A-90603C2C9025 • ios • com.apple.CoreSimulator.SimRuntime.iOS-16-2 (simulator)
• macOS (desktop) • macos • darwin-arm64 • macOS 13.0.1 22A400 darwin-arm64
• Chrome (web) • chrome • web-javascript • Google Chrome 108.0.5359.98
[✓] HTTP Host Availability
• All required HTTP hosts are available
• No issues found!

