Add missing features to `DefaultTextStyleTransition` and `AnimatedDefaultTextStyle` (#51517)
diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart
index 7f8d105..19aa171 100644
--- a/packages/flutter/lib/src/material/material.dart
+++ b/packages/flutter/lib/src/material/material.dart
@@ -350,7 +350,7 @@
);
Widget contents = widget.child;
if (contents != null) {
- contents = AnimatedDefaultTextStyle(
+ contents = AnimatedDefaultTextStyle.merge(
style: widget.textStyle ?? Theme.of(context).textTheme.bodyText2,
duration: widget.animationDuration,
child: contents,
diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart
index 99757be..3e2300d 100644
--- a/packages/flutter/lib/src/widgets/implicit_animations.dart
+++ b/packages/flutter/lib/src/widgets/implicit_animations.dart
@@ -1582,14 +1582,67 @@
/// See [DefaultTextStyle.maxLines] for more details.
final int maxLines;
- /// The strategy to use when calculating the width of the Text.
- ///
- /// See [TextWidthBasis] for possible values and their implications.
+ /// {@macro lutter.widgets.text.DefaultTextStyle.tetWidthBasis}
final TextWidthBasis textWidthBasis;
/// {@macro flutter.dart:ui.textHeightBehavior}
final ui.TextHeightBehavior textHeightBehavior;
+ /// Creates an animated default text style that overrides the text styles in
+ /// scope at this point in the widget tree.
+ ///
+ /// The given [style] is merged with the [style] from the default text style
+ /// for the [BuildContext] where the widget is inserted, and any of the other
+ /// arguments that are not null replace the corresponding properties on that
+ /// same default text style.
+ ///
+ /// This constructor cannot be used to override the [maxLines] property of the
+ /// ancestor with the value null, since null here is used to mean "defer to
+ /// ancestor". To replace a non-null [maxLines] from an ancestor with the null
+ /// value (to remove the restriction on number of lines), manually obtain the
+ /// ambient [DefaultTextStyle] using [DefaultTextStyle.of], then create a new
+ /// [DefaultTextStyle] using the [new DefaultTextStyle] constructor directly.
+ /// See the source below for an example of how to do this (since that's
+ /// essentially what this constructor does).
+ ///
+ /// Since the ancestor may not have been an AnimatedDefaultTextStyle, the
+ /// [duration] property is required.
+ static Widget merge({
+ Key key,
+ @required Widget child,
+ TextStyle style,
+ TextAlign textAlign,
+ bool softWrap,
+ TextOverflow overflow,
+ int maxLines,
+ TextWidthBasis textWidthBasis,
+ ui.TextHeightBehavior textHeightBehavior,
+ Curve curve = Curves.linear,
+ @required Duration duration,
+ VoidCallback onEnd,
+ }) {
+ assert(child != null);
+ return Builder(
+ builder: (BuildContext context) {
+ final DefaultTextStyle parent = DefaultTextStyle.of(context);
+ return AnimatedDefaultTextStyle(
+ key: key,
+ style: parent.style.merge(style),
+ textAlign: textAlign ?? parent.textAlign,
+ softWrap: softWrap ?? parent.softWrap,
+ overflow: overflow ?? parent.overflow,
+ maxLines: maxLines ?? parent.maxLines,
+ textWidthBasis: textWidthBasis ?? parent.textWidthBasis,
+ textHeightBehavior: textHeightBehavior ?? parent.textHeightBehavior,
+ duration: duration,
+ curve: curve,
+ onEnd: onEnd,
+ child: child,
+ );
+ },
+ );
+ }
+
@override
_AnimatedDefaultTextStyleState createState() => _AnimatedDefaultTextStyleState();
diff --git a/packages/flutter/lib/src/widgets/text.dart b/packages/flutter/lib/src/widgets/text.dart
index 70cea57..198230d 100644
--- a/packages/flutter/lib/src/widgets/text.dart
+++ b/packages/flutter/lib/src/widgets/text.dart
@@ -95,6 +95,7 @@
TextOverflow overflow,
int maxLines,
TextWidthBasis textWidthBasis,
+ ui.TextHeightBehavior textHeightBehavior,
@required Widget child,
}) {
assert(child != null);
@@ -109,6 +110,7 @@
overflow: overflow ?? parent.overflow,
maxLines: maxLines ?? parent.maxLines,
textWidthBasis: textWidthBasis ?? parent.textWidthBasis,
+ textHeightBehavior: textHeightBehavior ?? parent.textHeightBehavior,
child: child,
);
},
@@ -140,9 +142,11 @@
/// [Text.maxLines].
final int maxLines;
+ /// {@template flutter.widgets.text.DefaultTextStyle.tetWidthBasis}
/// The strategy to use when calculating the width of the Text.
///
/// See [TextWidthBasis] for possible values and their implications.
+ /// {@endtemplate}
final TextWidthBasis textWidthBasis;
/// {@macro flutter.dart:ui.textHeightBehavior}
diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart
index 72093ce..39fe5b2 100644
--- a/packages/flutter/lib/src/widgets/transitions.dart
+++ b/packages/flutter/lib/src/widgets/transitions.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:math' as math;
+import 'dart:ui' as ui show TextHeightBehavior;
import 'package:flutter/rendering.dart';
import 'package:vector_math/vector_math_64.dart' show Matrix4;
@@ -969,8 +970,11 @@
this.softWrap = true,
this.overflow = TextOverflow.clip,
this.maxLines,
+ this.textWidthBasis = TextWidthBasis.parent,
+ this.textHeightBehavior,
}) : assert(style != null),
assert(child != null),
+ assert(textWidthBasis != null),
super(key: key, listenable: style);
/// The animation that controls the descendants' text style.
@@ -993,6 +997,14 @@
/// See [DefaultTextStyle.maxLines] for more details.
final int maxLines;
+ /// The strategy to use when calculating the width of the Text.
+ ///
+ /// See [TextWidthBasis] for possible values and their implications.
+ final TextWidthBasis textWidthBasis;
+
+ /// {@macro flutter.dart:ui.textHeightBehavior}
+ final ui.TextHeightBehavior textHeightBehavior;
+
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.child}
@@ -1006,6 +1018,8 @@
softWrap: softWrap,
overflow: overflow,
maxLines: maxLines,
+ textWidthBasis: textWidthBasis,
+ textHeightBehavior: textHeightBehavior,
child: child,
);
}
diff --git a/packages/flutter/test/widgets/implicit_animations_test.dart b/packages/flutter/test/widgets/implicit_animations_test.dart
index 133dd3f..a065af9 100644
--- a/packages/flutter/test/widgets/implicit_animations_test.dart
+++ b/packages/flutter/test/widgets/implicit_animations_test.dart
@@ -289,6 +289,36 @@
expect(mockOnEndFunction.called, 1);
});
+ testWidgets('AnimatedDefaultTextStyle merge test', (WidgetTester tester) async {
+ const Key animatedKey = Key('animatedStyle');
+ await tester.pumpWidget(
+ Directionality(
+ textDirection: TextDirection.rtl,
+ child: DefaultTextStyle(
+ style: const TextStyle(fontSize: 1234),
+ textHeightBehavior: const TextHeightBehavior(
+ applyHeightToFirstAscent: false,
+ ),
+ maxLines: 10,
+ softWrap: true,
+ child: AnimatedDefaultTextStyle.merge(
+ key: animatedKey,
+ maxLines: 20,
+ duration: const Duration(seconds: 10),
+ child: const Text('woah!'),
+ ),
+ ),
+ )
+ );
+ await tester.pump();
+
+ final Finder animatedDefaultTextStyleFinder = find.byKey(animatedKey);
+ AnimatedDefaultTextStyle getAnimatedDefautTextStyleWidget(Finder finder) => tester.widget<AnimatedDefaultTextStyle>(finder);
+ expect(getAnimatedDefautTextStyleWidget(animatedDefaultTextStyleFinder).textHeightBehavior, const TextHeightBehavior(applyHeightToFirstAscent: false,));
+ expect(getAnimatedDefautTextStyleWidget(animatedDefaultTextStyleFinder).softWrap, true);
+ expect(getAnimatedDefautTextStyleWidget(animatedDefaultTextStyleFinder).maxLines, 20);
+ });
+
testWidgets('AnimatedPhysicalModel onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap(
child: TestAnimatedWidget(
diff --git a/packages/flutter/test/widgets/transitions_test.dart b/packages/flutter/test/widgets/transitions_test.dart
index 82662c4..0ee1f14 100644
--- a/packages/flutter/test/widgets/transitions_test.dart
+++ b/packages/flutter/test/widgets/transitions_test.dart
@@ -408,4 +408,44 @@
expect(_getOpacity(tester, 'Fade In'), 1.0);
});
});
+
+ testWidgets('DefaultTextStyleTransition builds fully featured DefaultTextStyle', (WidgetTester tester) async {
+ const DefaultTextStyleTransition styleTransition = DefaultTextStyleTransition(
+ style: AlwaysStoppedAnimation<TextStyle>(TextStyle()),
+ child: Text('step on legos!'),
+ textAlign: TextAlign.right,
+ softWrap: false,
+ overflow: TextOverflow.fade,
+ maxLines: 5,
+ textWidthBasis: TextWidthBasis.longestLine,
+ textHeightBehavior: TextHeightBehavior(
+ applyHeightToFirstAscent: false,
+ applyHeightToLastDescent: false,
+ ),
+ );
+
+ expect((styleTransition.child as Text).data, 'step on legos!');
+ expect(styleTransition.textAlign, TextAlign.right);
+ expect(styleTransition.softWrap, false);
+ expect(styleTransition.overflow, TextOverflow.fade);
+ expect(styleTransition.maxLines, 5);
+ expect(styleTransition.textWidthBasis, TextWidthBasis.longestLine);
+ expect(styleTransition.textHeightBehavior, const TextHeightBehavior(
+ applyHeightToFirstAscent: false,
+ applyHeightToLastDescent: false,
+ ));
+
+ final DefaultTextStyle style = styleTransition.build(null) as DefaultTextStyle;
+
+ expect((style.child as Text).data, 'step on legos!');
+ expect(style.textAlign, TextAlign.right);
+ expect(style.softWrap, false);
+ expect(style.overflow, TextOverflow.fade);
+ expect(style.maxLines, 5);
+ expect(style.textWidthBasis, TextWidthBasis.longestLine);
+ expect(style.textHeightBehavior, const TextHeightBehavior(
+ applyHeightToFirstAscent: false,
+ applyHeightToLastDescent: false,
+ ));
+ });
}