Remove textScaleFactor
dependent logic from AppBar
(#128112)
I am trying to remove `textScaleFactor`-dependent logic from the framework since it's likely going to be deprecated, hopefully the original logic isn't from the material spec. I stole the sample code from https://github.com/flutter/flutter/pull/125038 and here are the screenshots (`textScaleFactor = 3.0`). Internal Tests: **no relevant test failures** | Medium | Large | | --------------- | --------------- | |  |  |
This commit is contained in:
parent
257c4eed43
commit
73e1f23426
@ -79,7 +79,7 @@ class _MediumScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
||||
${textStyle('md.comp.top-app-bar.medium.headline')}?.apply(color: ${color('md.comp.top-app-bar.medium.headline.color')});
|
||||
|
||||
@override
|
||||
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20);
|
||||
EdgeInsetsGeometry get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20);
|
||||
}
|
||||
|
||||
class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
||||
@ -102,7 +102,7 @@ class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
||||
${textStyle('md.comp.top-app-bar.large.headline')}?.apply(color: ${color('md.comp.top-app-bar.large.headline.color')});
|
||||
|
||||
@override
|
||||
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28);
|
||||
EdgeInsetsGeometry get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28);
|
||||
}
|
||||
''';
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ import 'theme.dart';
|
||||
// late String _logoAsset;
|
||||
// double _myToolbarHeight = 250.0;
|
||||
|
||||
typedef _FlexibleConfigBuilder = _ScrollUnderFlexibleConfig Function(BuildContext);
|
||||
|
||||
const double _kLeadingWidth = kToolbarHeight; // So the leading button is square.
|
||||
const double _kMaxTitleTextScaleFactor = 1.34; // TODO(perc): Add link to Material spec when available, https://github.com/flutter/flutter/issues/58769.
|
||||
|
||||
@ -1259,17 +1261,15 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
|
||||
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
|
||||
? clampDouble(visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight), 0.0, 1.0)
|
||||
: 1.0;
|
||||
final Widget? effectiveTitle;
|
||||
if (variant == _SliverAppVariant.small) {
|
||||
effectiveTitle = title;
|
||||
} else {
|
||||
effectiveTitle = AnimatedOpacity(
|
||||
final Widget? effectiveTitle = switch (variant) {
|
||||
_SliverAppVariant.small => title,
|
||||
_SliverAppVariant.medium || _SliverAppVariant.large => AnimatedOpacity(
|
||||
opacity: isScrolledUnder ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: const Cubic(0.2, 0.0, 0.0, 1.0),
|
||||
child: title,
|
||||
);
|
||||
}
|
||||
),
|
||||
};
|
||||
|
||||
final Widget appBar = FlexibleSpaceBar.createSettings(
|
||||
minExtent: minExtent,
|
||||
@ -1971,8 +1971,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
|
||||
effectiveFlexibleSpace = widget.flexibleSpace ?? _ScrollUnderFlexibleSpace(
|
||||
title: widget.title,
|
||||
foregroundColor: widget.foregroundColor,
|
||||
variant: _ScrollUnderFlexibleVariant.medium,
|
||||
primary: widget.primary,
|
||||
configBuilder: _MediumScrollUnderFlexibleConfig.new,
|
||||
titleTextStyle: widget.titleTextStyle,
|
||||
bottomHeight: bottomHeight,
|
||||
);
|
||||
@ -1984,8 +1983,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
|
||||
effectiveFlexibleSpace = widget.flexibleSpace ?? _ScrollUnderFlexibleSpace(
|
||||
title: widget.title,
|
||||
foregroundColor: widget.foregroundColor,
|
||||
variant: _ScrollUnderFlexibleVariant.large,
|
||||
primary: widget.primary,
|
||||
configBuilder: _LargeScrollUnderFlexibleConfig.new,
|
||||
titleTextStyle: widget.titleTextStyle,
|
||||
bottomHeight: bottomHeight,
|
||||
);
|
||||
@ -2081,79 +2079,48 @@ class _RenderAppBarTitleBox extends RenderAligningShiftedBox {
|
||||
}
|
||||
}
|
||||
|
||||
enum _ScrollUnderFlexibleVariant { medium, large }
|
||||
|
||||
class _ScrollUnderFlexibleSpace extends StatelessWidget {
|
||||
const _ScrollUnderFlexibleSpace({
|
||||
this.title,
|
||||
this.foregroundColor,
|
||||
required this.variant,
|
||||
this.primary = true,
|
||||
required this.configBuilder,
|
||||
this.titleTextStyle,
|
||||
required this.bottomHeight,
|
||||
});
|
||||
|
||||
final Widget? title;
|
||||
final Color? foregroundColor;
|
||||
final _ScrollUnderFlexibleVariant variant;
|
||||
final bool primary;
|
||||
final _FlexibleConfigBuilder configBuilder;
|
||||
final TextStyle? titleTextStyle;
|
||||
final double bottomHeight;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
late final ThemeData theme = Theme.of(context);
|
||||
late final AppBarTheme appBarTheme = AppBarTheme.of(context);
|
||||
final AppBarTheme defaults = theme.useMaterial3 ? _AppBarDefaultsM3(context) : _AppBarDefaultsM2(context);
|
||||
late final AppBarTheme defaults = Theme.of(context).useMaterial3 ? _AppBarDefaultsM3(context) : _AppBarDefaultsM2(context);
|
||||
final double textScaleFactor = math.min(MediaQuery.textScaleFactorOf(context), _kMaxTitleTextScaleFactor); // TODO(tahatesser): Add link to Material spec when available, https://github.com/flutter/flutter/issues/58769.
|
||||
final FlexibleSpaceBarSettings settings = context.dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>()!;
|
||||
final double topPadding = primary ? MediaQuery.viewPaddingOf(context).top : 0;
|
||||
final double collapsedHeight = settings.minExtent - topPadding - bottomHeight;
|
||||
final double scrollUnderHeight = settings.maxExtent - (settings.minExtent / textScaleFactor) + bottomHeight;
|
||||
final _ScrollUnderFlexibleConfig config;
|
||||
switch (variant) {
|
||||
case _ScrollUnderFlexibleVariant.medium:
|
||||
config = _MediumScrollUnderFlexibleConfig(context);
|
||||
case _ScrollUnderFlexibleVariant.large:
|
||||
config = _LargeScrollUnderFlexibleConfig(context);
|
||||
}
|
||||
final _ScrollUnderFlexibleConfig config = configBuilder(context);
|
||||
assert(
|
||||
config.expandedTitlePadding.isNonNegative,
|
||||
'The _ExpandedTitleWithPadding widget assumes that the expanded title padding is non-negative. '
|
||||
'Update its implementation to handle negative padding.',
|
||||
);
|
||||
|
||||
late final Widget? expandedTitle;
|
||||
if (title != null) {
|
||||
final TextStyle? expandedTextStyle = titleTextStyle
|
||||
?? appBarTheme.titleTextStyle
|
||||
?? config.expandedTextStyle?.copyWith(
|
||||
color: foregroundColor ?? appBarTheme.foregroundColor ?? defaults.foregroundColor,
|
||||
);
|
||||
expandedTitle = config.expandedTextStyle != null
|
||||
? DefaultTextStyle(
|
||||
style: expandedTextStyle!,
|
||||
child: title!,
|
||||
)
|
||||
: title;
|
||||
}
|
||||
final TextStyle? expandedTextStyle = titleTextStyle
|
||||
?? appBarTheme.titleTextStyle
|
||||
?? config.expandedTextStyle?.copyWith(color: foregroundColor ?? appBarTheme.foregroundColor ?? defaults.foregroundColor);
|
||||
|
||||
EdgeInsetsGeometry expandedTitlePadding() {
|
||||
final EdgeInsets padding = config.expandedTitlePadding!.resolve(Directionality.of(context));
|
||||
if (bottomHeight > 0) {
|
||||
return EdgeInsets.fromLTRB(padding.left, 0, padding.right, bottomHeight);
|
||||
}
|
||||
if (theme.useMaterial3) {
|
||||
final TextStyle textStyle = config.expandedTextStyle!;
|
||||
// Substract the bottom line height from the bottom padding.
|
||||
// TODO(tahatesser): Figure out why this is done.
|
||||
// https://github.com/flutter/flutter/issues/120672
|
||||
final double adjustBottomPadding = padding.bottom
|
||||
- (textStyle.fontSize! * textStyle.height! - textStyle.fontSize!) / 2;
|
||||
return EdgeInsets.fromLTRB(
|
||||
padding.left,
|
||||
0,
|
||||
padding.right,
|
||||
adjustBottomPadding / textScaleFactor,
|
||||
);
|
||||
}
|
||||
return padding;
|
||||
}
|
||||
final Widget? expandedTitle = switch ((title, expandedTextStyle)) {
|
||||
(null, _) => null,
|
||||
(final Widget title, null) => title,
|
||||
(final Widget title, final TextStyle textStyle) => DefaultTextStyle(style: textStyle, child: title),
|
||||
};
|
||||
|
||||
final EdgeInsets resolvedTitlePadding = config.expandedTitlePadding.resolve(Directionality.of(context));
|
||||
final EdgeInsetsGeometry expandedTitlePadding = bottomHeight > 0
|
||||
? resolvedTitlePadding.copyWith(bottom: 0)
|
||||
: resolvedTitlePadding;
|
||||
|
||||
// Set maximum text scale factor to [_kMaxTitleTextScaleFactor] for the
|
||||
// title to keep the visual hierarchy the same even with larger font
|
||||
@ -2162,35 +2129,167 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget {
|
||||
// `MediaQuery.textScaleFactorOf(context)`.
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
|
||||
// This column will assume the full height of the parent Stack.
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: collapsedHeight + topPadding),
|
||||
),
|
||||
Padding(padding: EdgeInsets.only(top: settings.minExtent - bottomHeight)),
|
||||
Flexible(
|
||||
child: ClipRect(
|
||||
child: OverflowBox(
|
||||
minHeight: scrollUnderHeight,
|
||||
maxHeight: scrollUnderHeight,
|
||||
alignment: Alignment.bottomLeft,
|
||||
child: Container(
|
||||
alignment: AlignmentDirectional.bottomStart,
|
||||
padding: expandedTitlePadding(),
|
||||
child: expandedTitle,
|
||||
),
|
||||
child: _ExpandedTitleWithPadding(
|
||||
padding: expandedTitlePadding,
|
||||
maxExtent: settings.maxExtent - settings.minExtent,
|
||||
child: expandedTitle,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Reserve space for AppBar.bottom, which is a sibling of this widget,
|
||||
// on the parent Stack.
|
||||
if (bottomHeight > 0) Padding(padding: EdgeInsets.only(bottom: bottomHeight)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// A widget that bottom-start aligns its child (the expanded title widget), and
|
||||
// insets the child according to the specified padding.
|
||||
//
|
||||
// This widget gives the child an infinite max height constraint, and will also
|
||||
// attempt to vertically limit the child's bounding box (not including the
|
||||
// padding) to within the y range [0, maxExtent], to make sure the child is
|
||||
// visible when the AppBar is fully expanded.
|
||||
class _ExpandedTitleWithPadding extends SingleChildRenderObjectWidget {
|
||||
const _ExpandedTitleWithPadding({
|
||||
required this.padding,
|
||||
required this.maxExtent,
|
||||
super.child,
|
||||
});
|
||||
|
||||
final EdgeInsetsGeometry padding;
|
||||
final double maxExtent;
|
||||
|
||||
@override
|
||||
_RenderExpandedTitleBox createRenderObject(BuildContext context) {
|
||||
final TextDirection textDirection = Directionality.of(context);
|
||||
return _RenderExpandedTitleBox(
|
||||
padding.resolve(textDirection),
|
||||
AlignmentDirectional.bottomStart.resolve(textDirection),
|
||||
maxExtent,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void updateRenderObject(BuildContext context, _RenderExpandedTitleBox renderObject) {
|
||||
final TextDirection textDirection = Directionality.of(context);
|
||||
renderObject
|
||||
..padding = padding.resolve(textDirection)
|
||||
..titleAlignment = AlignmentDirectional.bottomStart.resolve(textDirection)
|
||||
..maxExtent = maxExtent;
|
||||
}
|
||||
}
|
||||
|
||||
class _RenderExpandedTitleBox extends RenderShiftedBox {
|
||||
_RenderExpandedTitleBox(this._padding, this._titleAlignment, this._maxExtent, super.child);
|
||||
|
||||
EdgeInsets get padding => _padding;
|
||||
EdgeInsets _padding;
|
||||
set padding(EdgeInsets value) {
|
||||
if (_padding == value) {
|
||||
return;
|
||||
}
|
||||
assert(value.isNonNegative);
|
||||
_padding = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
Alignment get titleAlignment => _titleAlignment;
|
||||
Alignment _titleAlignment;
|
||||
set titleAlignment(Alignment value) {
|
||||
if (_titleAlignment == value) {
|
||||
return;
|
||||
}
|
||||
_titleAlignment = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
double get maxExtent => _maxExtent;
|
||||
double _maxExtent;
|
||||
set maxExtent(double value) {
|
||||
if (_maxExtent == value) {
|
||||
return;
|
||||
}
|
||||
_maxExtent = value;
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
@override
|
||||
double computeMaxIntrinsicHeight(double width) {
|
||||
final RenderBox? child = this.child;
|
||||
return child == null ? 0.0 : child.getMaxIntrinsicHeight(math.max(0, width - padding.horizontal)) + padding.vertical;
|
||||
}
|
||||
|
||||
@override
|
||||
double computeMaxIntrinsicWidth(double height) {
|
||||
final RenderBox? child = this.child;
|
||||
return child == null ? 0.0 : child.getMaxIntrinsicWidth(double.infinity) + padding.horizontal;
|
||||
}
|
||||
|
||||
@override
|
||||
double computeMinIntrinsicHeight(double width) {
|
||||
final RenderBox? child = this.child;
|
||||
return child == null ? 0.0 : child.getMinIntrinsicHeight(math.max(0, width - padding.horizontal)) + padding.vertical;
|
||||
}
|
||||
|
||||
@override
|
||||
double computeMinIntrinsicWidth(double height) {
|
||||
final RenderBox? child = this.child;
|
||||
return child == null ? 0.0 : child.getMinIntrinsicWidth(double.infinity) + padding.horizontal;
|
||||
}
|
||||
|
||||
Size _computeSize(BoxConstraints constraints, ChildLayouter layoutChild) {
|
||||
final RenderBox? child = this.child;
|
||||
if (child == null) {
|
||||
return Size.zero;
|
||||
}
|
||||
layoutChild(child, constraints.widthConstraints().deflate(padding));
|
||||
return constraints.biggest;
|
||||
}
|
||||
|
||||
@override
|
||||
Size computeDryLayout(BoxConstraints constraints) => _computeSize(constraints, ChildLayoutHelper.dryLayoutChild);
|
||||
|
||||
@override
|
||||
void performLayout() {
|
||||
final RenderBox? child = this.child;
|
||||
if (child == null) {
|
||||
this.size = constraints.smallest;
|
||||
return;
|
||||
}
|
||||
final Size size = this.size = _computeSize(constraints, ChildLayoutHelper.layoutChild);
|
||||
final Size childSize = child.size;
|
||||
|
||||
assert(padding.isNonNegative);
|
||||
assert(titleAlignment.y == 1.0);
|
||||
// yAdjustement is the minimum additional y offset to shift the child in
|
||||
// the visible vertical space when AppBar is fully expanded. The goal is to
|
||||
// prevent the expanded title from being clipped when the expanded title
|
||||
// widget + the bottom padding is too tall to fit in the flexible space (the
|
||||
// top padding is basically ignored since the expanded title is
|
||||
// bottom-aligned).
|
||||
final double yAdjustement = clampDouble(childSize.height + padding.bottom - maxExtent, 0, padding.bottom);
|
||||
final double offsetY = size.height - childSize.height - padding.bottom + yAdjustement;
|
||||
final double offsetX = (titleAlignment.x + 1) / 2 * (size.width - padding.horizontal - childSize.width) + padding.left;
|
||||
|
||||
final BoxParentData childParentData = child.parentData! as BoxParentData;
|
||||
childParentData.offset = Offset(offsetX, offsetY);
|
||||
}
|
||||
}
|
||||
|
||||
mixin _ScrollUnderFlexibleConfig {
|
||||
TextStyle? get collapsedTextStyle;
|
||||
TextStyle? get expandedTextStyle;
|
||||
EdgeInsetsGeometry? get expandedTitlePadding;
|
||||
EdgeInsetsGeometry get expandedTitlePadding;
|
||||
}
|
||||
|
||||
// Hand coded defaults based on Material Design 2.
|
||||
@ -2298,7 +2397,7 @@ class _MediumScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
||||
_textTheme.headlineSmall?.apply(color: _colors.onSurface);
|
||||
|
||||
@override
|
||||
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20);
|
||||
EdgeInsetsGeometry get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 20);
|
||||
}
|
||||
|
||||
class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
||||
@ -2321,7 +2420,7 @@ class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
||||
_textTheme.headlineMedium?.apply(color: _colors.onSurface);
|
||||
|
||||
@override
|
||||
EdgeInsetsGeometry? get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28);
|
||||
EdgeInsetsGeometry get expandedTitlePadding => const EdgeInsets.fromLTRB(16, 0, 16, 28);
|
||||
}
|
||||
|
||||
// END GENERATED TOKEN PROPERTIES - AppBar
|
||||
|
@ -2215,7 +2215,7 @@ class _ChipDefaultsM3 extends ChipThemeData {
|
||||
EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0);
|
||||
|
||||
/// The chip at text scale 1 starts with 8px on each side and as text scaling
|
||||
/// gets closer to 2 the label padding is linearly interpolated from 8px to 4px.
|
||||
/// gets closer to 2, the label padding is linearly interpolated from 8px to 4px.
|
||||
/// Once the widget has a text scaling of 2 or higher than the label padding
|
||||
/// remains 4px.
|
||||
@override
|
||||
|
@ -62,6 +62,15 @@ TextStyle? iconStyle(WidgetTester tester, IconData icon) {
|
||||
return iconRichText.text.style;
|
||||
}
|
||||
|
||||
void _verifyTextNotClipped(Finder textFinder, WidgetTester tester) {
|
||||
final Rect clipRect = tester.getRect(find.ancestor(of: textFinder, matching: find.byType(ClipRect)).first);
|
||||
final Rect textRect = tester.getRect(textFinder);
|
||||
expect(textRect.top, inInclusiveRange(clipRect.top, clipRect.bottom));
|
||||
expect(textRect.bottom, inInclusiveRange(clipRect.top, clipRect.bottom));
|
||||
expect(textRect.left, inInclusiveRange(clipRect.left, clipRect.right));
|
||||
expect(textRect.right, inInclusiveRange(clipRect.left, clipRect.right));
|
||||
}
|
||||
|
||||
double appBarHeight(WidgetTester tester) => tester.getSize(find.byType(AppBar, skipOffstage: false)).height;
|
||||
double appBarTop(WidgetTester tester) => tester.getTopLeft(find.byType(AppBar, skipOffstage: false)).dy;
|
||||
double appBarBottom(WidgetTester tester) => tester.getBottomLeft(find.byType(AppBar, skipOffstage: false)).dy;
|
||||
@ -1138,7 +1147,9 @@ void main() {
|
||||
// Test the expanded title is positioned correctly.
|
||||
final Offset titleOffset = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleOffset.dx, 16.0);
|
||||
expect(titleOffset.dy, closeTo(96.0, 0.1));
|
||||
expect(titleOffset.dy, 96.0);
|
||||
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
// Test the expanded title default color.
|
||||
expect(
|
||||
@ -1223,8 +1234,14 @@ void main() {
|
||||
// Test the expanded title is positioned correctly.
|
||||
final Offset titleOffset = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleOffset.dx, 16.0);
|
||||
expect(titleOffset.dy, closeTo(128.0, 0.1));
|
||||
|
||||
final RenderSliver renderSliverAppBar = tester.renderObject(find.byType(SliverAppBar));
|
||||
// The expanded title and the bottom padding fits in the flexible space.
|
||||
expect(
|
||||
titleOffset.dy,
|
||||
renderSliverAppBar.geometry!.scrollExtent - 28.0,
|
||||
reason: 'bottom padding of a large expanded title should be 28.',
|
||||
);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
// Test the expanded title default color.
|
||||
expect(
|
||||
@ -4704,13 +4721,16 @@ void main() {
|
||||
await tester.pumpWidget(buildAppBar());
|
||||
|
||||
final Finder expandedTitle = find.text(title).first;
|
||||
expect(tester.getRect(expandedTitle).height, closeTo(31.9, 0.1));
|
||||
expect(tester.getRect(expandedTitle).height, 32.0);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 2.0));
|
||||
expect(tester.getRect(expandedTitle).height, closeTo(43.0, 0.1));
|
||||
expect(tester.getRect(expandedTitle).height, 43.0);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0));
|
||||
expect(tester.getRect(expandedTitle).height, closeTo(43.0, 0.1));
|
||||
expect(tester.getRect(expandedTitle).height, 43.0);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar.large expanded title has upper limit on text scaling', (WidgetTester tester) async {
|
||||
@ -4787,24 +4807,16 @@ void main() {
|
||||
await tester.pumpWidget(buildAppBar());
|
||||
|
||||
final Finder expandedTitle = find.text(title).first;
|
||||
Offset titleTop = tester.getTopLeft(expandedTitle);
|
||||
expect(titleTop.dy, 64.0);
|
||||
Offset titleBottom = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleBottom.dy, closeTo(96.0, 0.1));
|
||||
expect(tester.getBottomLeft(expandedTitle).dy, 96.0);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 2.0));
|
||||
|
||||
titleTop = tester.getTopLeft(expandedTitle);
|
||||
expect(titleTop.dy, closeTo(57.0, 0.1));
|
||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleBottom.dy, closeTo(100.0, 0.1));
|
||||
expect(tester.getBottomLeft(expandedTitle).dy, 107.0);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0));
|
||||
|
||||
titleTop = tester.getTopLeft(expandedTitle);
|
||||
expect(titleTop.dy, closeTo(57.0, 0.1));
|
||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleBottom.dy, closeTo(100.0, 0.1));
|
||||
expect(tester.getBottomLeft(expandedTitle).dy, 107.0);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar.large expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async {
|
||||
@ -4834,29 +4846,28 @@ void main() {
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildAppBar());
|
||||
// TODO(tahatesser): https://github.com/flutter/flutter/issues/99933
|
||||
// A bug in the HTML renderer and/or Chrome 96+ causes a
|
||||
// discrepancy in the paragraph height.
|
||||
const bool hasIssue99933 = kIsWeb && !bool.fromEnvironment('FLUTTER_WEB_USE_SKIA');
|
||||
final Finder expandedTitle = find.text(title).first;
|
||||
Offset titleTop = tester.getTopLeft(expandedTitle);
|
||||
expect(titleTop.dy, closeTo(hasIssue99933 ? 91.0 : 92.0, 0.1));
|
||||
Offset titleBottom = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleBottom.dy, closeTo(128.0, 0.1));
|
||||
final RenderSliver renderSliverAppBar = tester.renderObject(find.byType(SliverAppBar));
|
||||
expect(
|
||||
tester.getBottomLeft(expandedTitle).dy,
|
||||
renderSliverAppBar.geometry!.scrollExtent - 28.0,
|
||||
reason: 'bottom padding of a large expanded title should be 28.',
|
||||
);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 2.0));
|
||||
expect(
|
||||
tester.getBottomLeft(expandedTitle).dy,
|
||||
renderSliverAppBar.geometry!.scrollExtent - 28.0,
|
||||
reason: 'bottom padding of a large expanded title should be 28.',
|
||||
);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
|
||||
titleTop = tester.getTopLeft(expandedTitle);
|
||||
expect(titleTop.dy, closeTo(86.1, 0.1));
|
||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleBottom.dy, closeTo(134.1, 0.1));
|
||||
|
||||
// The bottom padding of the expanded title needs to be reduced for it to be
|
||||
// fully visible.
|
||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0));
|
||||
|
||||
titleTop = tester.getTopLeft(expandedTitle);
|
||||
expect(titleTop.dy, closeTo(86.1, 0.1));
|
||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
||||
expect(titleBottom.dy, closeTo(134.1, 0.1));
|
||||
expect(tester.getBottomLeft(expandedTitle).dy, 124.0);
|
||||
_verifyTextNotClipped(expandedTitle, tester);
|
||||
});
|
||||
|
||||
group('AppBar.forceMaterialTransparency', () {
|
||||
|
Loading…
x
Reference in New Issue
Block a user