mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Feat: Animate fill for material app bar (#163913)
Feat: Animate fill for material app bar fixes: #162988 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
This commit is contained in:
parent
708c0eb185
commit
b0f5c8ce03
@ -221,6 +221,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.useDefaultSemanticsOrder = true,
|
||||
this.clipBehavior,
|
||||
this.actionsPadding,
|
||||
this.animateColor = false,
|
||||
}) : assert(elevation == null || elevation >= 0.0),
|
||||
preferredSize = _PreferredAppBarSize(toolbarHeight, bottom?.preferredSize.height);
|
||||
|
||||
@ -773,6 +774,9 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
/// {@endtemplate}
|
||||
final EdgeInsetsGeometry? actionsPadding;
|
||||
|
||||
/// Whether the color should be animated.
|
||||
final bool animateColor;
|
||||
|
||||
bool _getEffectiveCenterTitle(ThemeData theme) {
|
||||
bool platformCenter() {
|
||||
switch (theme.platform) {
|
||||
@ -1213,6 +1217,7 @@ class _AppBarState extends State<AppBar> {
|
||||
??
|
||||
(theme.useMaterial3 ? theme.colorScheme.surfaceTint : null),
|
||||
shape: widget.shape ?? appBarTheme.shape ?? defaults.shape,
|
||||
animateColor: widget.animateColor,
|
||||
child: Semantics(explicitChildNodes: true, child: appBar),
|
||||
),
|
||||
),
|
||||
|
@ -204,6 +204,7 @@ class Material extends StatefulWidget {
|
||||
this.clipBehavior = Clip.none,
|
||||
this.animationDuration = kThemeChangeDuration,
|
||||
this.child,
|
||||
this.animateColor = false,
|
||||
}) : assert(elevation >= 0.0),
|
||||
assert(!(shape != null && borderRadius != null)),
|
||||
assert(!(identical(type, MaterialType.circle) && (borderRadius != null || shape != null)));
|
||||
@ -218,6 +219,9 @@ class Material extends StatefulWidget {
|
||||
/// the shape is rectangular, and the default color.
|
||||
final MaterialType type;
|
||||
|
||||
/// Whether the color should be animated.
|
||||
final bool animateColor;
|
||||
|
||||
/// {@template flutter.material.material.elevation}
|
||||
/// The z-coordinate at which to place this material relative to its parent.
|
||||
///
|
||||
@ -522,7 +526,7 @@ class _MaterialState extends State<Material> with TickerProviderStateMixin {
|
||||
elevation: widget.elevation,
|
||||
color: color,
|
||||
shadowColor: modelShadowColor,
|
||||
animateColor: false,
|
||||
animateColor: widget.animateColor,
|
||||
child: contents,
|
||||
);
|
||||
}
|
||||
|
@ -2244,17 +2244,21 @@ void main() {
|
||||
required double contentHeight,
|
||||
bool reverse = false,
|
||||
bool includeFlexibleSpace = false,
|
||||
bool animateColor = false,
|
||||
double? scrolledUnderElevation,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: scrolledUnderElevation,
|
||||
backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||
return states.contains(MaterialState.scrolledUnder) ? scrolledColor : defaultColor;
|
||||
}),
|
||||
title: const Text('AppBar'),
|
||||
flexibleSpace:
|
||||
includeFlexibleSpace ? const FlexibleSpaceBar(title: Text('FlexibleSpace')) : null,
|
||||
animateColor: animateColor,
|
||||
),
|
||||
body: ListView(
|
||||
reverse: reverse,
|
||||
@ -2339,6 +2343,39 @@ void main() {
|
||||
expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
|
||||
});
|
||||
|
||||
testWidgets('backgroundColor animation', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
buildAppBar(contentHeight: 1200.0, scrolledUnderElevation: 0, animateColor: true),
|
||||
);
|
||||
|
||||
expect(getAppBarAnimatedBackgroundColor(tester), defaultColor);
|
||||
|
||||
TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
|
||||
await gesture.moveBy(const Offset(0.0, -kToolbarHeight));
|
||||
await gesture.up();
|
||||
await tester.pump();
|
||||
|
||||
expect(getAppBarAnimatedBackgroundColor(tester), defaultColor);
|
||||
await tester.pumpAndSettle();
|
||||
expect(getAppBarAnimatedBackgroundColor(tester), scrolledColor);
|
||||
|
||||
gesture = await tester.startGesture(const Offset(50.0, 300.0));
|
||||
await gesture.moveBy(const Offset(0.0, kToolbarHeight));
|
||||
await gesture.up();
|
||||
await tester.pump();
|
||||
|
||||
expect(getAppBarAnimatedBackgroundColor(tester), scrolledColor);
|
||||
|
||||
// Check intermediate color values.
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
expect(getAppBarAnimatedBackgroundColor(tester), isSameColorAs(const Color(0xFF00C33C)));
|
||||
await tester.pump(const Duration(milliseconds: 50));
|
||||
expect(getAppBarAnimatedBackgroundColor(tester), isSameColorAs(const Color(0xFF0039C6)));
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
expect(getAppBarAnimatedBackgroundColor(tester), defaultColor);
|
||||
});
|
||||
|
||||
testWidgets('backgroundColor with FlexibleSpace', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(buildAppBar(contentHeight: 1200.0, includeFlexibleSpace: true));
|
||||
|
||||
|
@ -5,6 +5,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
Finder findAppBarPhysicalModel() {
|
||||
return find.descendant(of: find.byType(AppBar), matching: find.byType(PhysicalModel)).first;
|
||||
}
|
||||
|
||||
Color? getAppBarAnimatedBackgroundColor(WidgetTester tester) {
|
||||
return tester.widget<PhysicalModel>(findAppBarPhysicalModel()).color;
|
||||
}
|
||||
|
||||
Finder findAppBarMaterial() {
|
||||
return find.descendant(of: find.byType(AppBar), matching: find.byType(Material)).first;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user