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')});
|
${textStyle('md.comp.top-app-bar.medium.headline')}?.apply(color: ${color('md.comp.top-app-bar.medium.headline.color')});
|
||||||
|
|
||||||
@override
|
@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 {
|
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')});
|
${textStyle('md.comp.top-app-bar.large.headline')}?.apply(color: ${color('md.comp.top-app-bar.large.headline.color')});
|
||||||
|
|
||||||
@override
|
@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;
|
// late String _logoAsset;
|
||||||
// double _myToolbarHeight = 250.0;
|
// double _myToolbarHeight = 250.0;
|
||||||
|
|
||||||
|
typedef _FlexibleConfigBuilder = _ScrollUnderFlexibleConfig Function(BuildContext);
|
||||||
|
|
||||||
const double _kLeadingWidth = kToolbarHeight; // So the leading button is square.
|
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.
|
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
|
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
|
||||||
? clampDouble(visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight), 0.0, 1.0)
|
? clampDouble(visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight), 0.0, 1.0)
|
||||||
: 1.0;
|
: 1.0;
|
||||||
final Widget? effectiveTitle;
|
final Widget? effectiveTitle = switch (variant) {
|
||||||
if (variant == _SliverAppVariant.small) {
|
_SliverAppVariant.small => title,
|
||||||
effectiveTitle = title;
|
_SliverAppVariant.medium || _SliverAppVariant.large => AnimatedOpacity(
|
||||||
} else {
|
|
||||||
effectiveTitle = AnimatedOpacity(
|
|
||||||
opacity: isScrolledUnder ? 1 : 0,
|
opacity: isScrolledUnder ? 1 : 0,
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
curve: const Cubic(0.2, 0.0, 0.0, 1.0),
|
curve: const Cubic(0.2, 0.0, 0.0, 1.0),
|
||||||
child: title,
|
child: title,
|
||||||
);
|
),
|
||||||
}
|
};
|
||||||
|
|
||||||
final Widget appBar = FlexibleSpaceBar.createSettings(
|
final Widget appBar = FlexibleSpaceBar.createSettings(
|
||||||
minExtent: minExtent,
|
minExtent: minExtent,
|
||||||
@ -1971,8 +1971,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
|
|||||||
effectiveFlexibleSpace = widget.flexibleSpace ?? _ScrollUnderFlexibleSpace(
|
effectiveFlexibleSpace = widget.flexibleSpace ?? _ScrollUnderFlexibleSpace(
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
foregroundColor: widget.foregroundColor,
|
foregroundColor: widget.foregroundColor,
|
||||||
variant: _ScrollUnderFlexibleVariant.medium,
|
configBuilder: _MediumScrollUnderFlexibleConfig.new,
|
||||||
primary: widget.primary,
|
|
||||||
titleTextStyle: widget.titleTextStyle,
|
titleTextStyle: widget.titleTextStyle,
|
||||||
bottomHeight: bottomHeight,
|
bottomHeight: bottomHeight,
|
||||||
);
|
);
|
||||||
@ -1984,8 +1983,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
|
|||||||
effectiveFlexibleSpace = widget.flexibleSpace ?? _ScrollUnderFlexibleSpace(
|
effectiveFlexibleSpace = widget.flexibleSpace ?? _ScrollUnderFlexibleSpace(
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
foregroundColor: widget.foregroundColor,
|
foregroundColor: widget.foregroundColor,
|
||||||
variant: _ScrollUnderFlexibleVariant.large,
|
configBuilder: _LargeScrollUnderFlexibleConfig.new,
|
||||||
primary: widget.primary,
|
|
||||||
titleTextStyle: widget.titleTextStyle,
|
titleTextStyle: widget.titleTextStyle,
|
||||||
bottomHeight: bottomHeight,
|
bottomHeight: bottomHeight,
|
||||||
);
|
);
|
||||||
@ -2081,79 +2079,48 @@ class _RenderAppBarTitleBox extends RenderAligningShiftedBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum _ScrollUnderFlexibleVariant { medium, large }
|
|
||||||
|
|
||||||
class _ScrollUnderFlexibleSpace extends StatelessWidget {
|
class _ScrollUnderFlexibleSpace extends StatelessWidget {
|
||||||
const _ScrollUnderFlexibleSpace({
|
const _ScrollUnderFlexibleSpace({
|
||||||
this.title,
|
this.title,
|
||||||
this.foregroundColor,
|
this.foregroundColor,
|
||||||
required this.variant,
|
required this.configBuilder,
|
||||||
this.primary = true,
|
|
||||||
this.titleTextStyle,
|
this.titleTextStyle,
|
||||||
required this.bottomHeight,
|
required this.bottomHeight,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Widget? title;
|
final Widget? title;
|
||||||
final Color? foregroundColor;
|
final Color? foregroundColor;
|
||||||
final _ScrollUnderFlexibleVariant variant;
|
final _FlexibleConfigBuilder configBuilder;
|
||||||
final bool primary;
|
|
||||||
final TextStyle? titleTextStyle;
|
final TextStyle? titleTextStyle;
|
||||||
final double bottomHeight;
|
final double bottomHeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
late final ThemeData theme = Theme.of(context);
|
|
||||||
late final AppBarTheme appBarTheme = AppBarTheme.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 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 FlexibleSpaceBarSettings settings = context.dependOnInheritedWidgetOfExactType<FlexibleSpaceBarSettings>()!;
|
||||||
final double topPadding = primary ? MediaQuery.viewPaddingOf(context).top : 0;
|
final _ScrollUnderFlexibleConfig config = configBuilder(context);
|
||||||
final double collapsedHeight = settings.minExtent - topPadding - bottomHeight;
|
assert(
|
||||||
final double scrollUnderHeight = settings.maxExtent - (settings.minExtent / textScaleFactor) + bottomHeight;
|
config.expandedTitlePadding.isNonNegative,
|
||||||
final _ScrollUnderFlexibleConfig config;
|
'The _ExpandedTitleWithPadding widget assumes that the expanded title padding is non-negative. '
|
||||||
switch (variant) {
|
'Update its implementation to handle negative padding.',
|
||||||
case _ScrollUnderFlexibleVariant.medium:
|
);
|
||||||
config = _MediumScrollUnderFlexibleConfig(context);
|
|
||||||
case _ScrollUnderFlexibleVariant.large:
|
|
||||||
config = _LargeScrollUnderFlexibleConfig(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
late final Widget? expandedTitle;
|
final TextStyle? expandedTextStyle = titleTextStyle
|
||||||
if (title != null) {
|
?? appBarTheme.titleTextStyle
|
||||||
final TextStyle? expandedTextStyle = titleTextStyle
|
?? config.expandedTextStyle?.copyWith(color: foregroundColor ?? appBarTheme.foregroundColor ?? defaults.foregroundColor);
|
||||||
?? appBarTheme.titleTextStyle
|
|
||||||
?? config.expandedTextStyle?.copyWith(
|
|
||||||
color: foregroundColor ?? appBarTheme.foregroundColor ?? defaults.foregroundColor,
|
|
||||||
);
|
|
||||||
expandedTitle = config.expandedTextStyle != null
|
|
||||||
? DefaultTextStyle(
|
|
||||||
style: expandedTextStyle!,
|
|
||||||
child: title!,
|
|
||||||
)
|
|
||||||
: title;
|
|
||||||
}
|
|
||||||
|
|
||||||
EdgeInsetsGeometry expandedTitlePadding() {
|
final Widget? expandedTitle = switch ((title, expandedTextStyle)) {
|
||||||
final EdgeInsets padding = config.expandedTitlePadding!.resolve(Directionality.of(context));
|
(null, _) => null,
|
||||||
if (bottomHeight > 0) {
|
(final Widget title, null) => title,
|
||||||
return EdgeInsets.fromLTRB(padding.left, 0, padding.right, bottomHeight);
|
(final Widget title, final TextStyle textStyle) => DefaultTextStyle(style: textStyle, child: title),
|
||||||
}
|
};
|
||||||
if (theme.useMaterial3) {
|
|
||||||
final TextStyle textStyle = config.expandedTextStyle!;
|
final EdgeInsets resolvedTitlePadding = config.expandedTitlePadding.resolve(Directionality.of(context));
|
||||||
// Substract the bottom line height from the bottom padding.
|
final EdgeInsetsGeometry expandedTitlePadding = bottomHeight > 0
|
||||||
// TODO(tahatesser): Figure out why this is done.
|
? resolvedTitlePadding.copyWith(bottom: 0)
|
||||||
// https://github.com/flutter/flutter/issues/120672
|
: resolvedTitlePadding;
|
||||||
final double adjustBottomPadding = padding.bottom
|
|
||||||
- (textStyle.fontSize! * textStyle.height! - textStyle.fontSize!) / 2;
|
|
||||||
return EdgeInsets.fromLTRB(
|
|
||||||
padding.left,
|
|
||||||
0,
|
|
||||||
padding.right,
|
|
||||||
adjustBottomPadding / textScaleFactor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return padding;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set maximum text scale factor to [_kMaxTitleTextScaleFactor] for the
|
// Set maximum text scale factor to [_kMaxTitleTextScaleFactor] for the
|
||||||
// title to keep the visual hierarchy the same even with larger font
|
// title to keep the visual hierarchy the same even with larger font
|
||||||
@ -2162,35 +2129,167 @@ class _ScrollUnderFlexibleSpace extends StatelessWidget {
|
|||||||
// `MediaQuery.textScaleFactorOf(context)`.
|
// `MediaQuery.textScaleFactorOf(context)`.
|
||||||
return MediaQuery(
|
return MediaQuery(
|
||||||
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
|
data: MediaQuery.of(context).copyWith(textScaleFactor: textScaleFactor),
|
||||||
|
// This column will assume the full height of the parent Stack.
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Padding(padding: EdgeInsets.only(top: settings.minExtent - bottomHeight)),
|
||||||
padding: EdgeInsets.only(top: collapsedHeight + topPadding),
|
|
||||||
),
|
|
||||||
Flexible(
|
Flexible(
|
||||||
child: ClipRect(
|
child: ClipRect(
|
||||||
child: OverflowBox(
|
child: _ExpandedTitleWithPadding(
|
||||||
minHeight: scrollUnderHeight,
|
padding: expandedTitlePadding,
|
||||||
maxHeight: scrollUnderHeight,
|
maxExtent: settings.maxExtent - settings.minExtent,
|
||||||
alignment: Alignment.bottomLeft,
|
child: expandedTitle,
|
||||||
child: Container(
|
|
||||||
alignment: AlignmentDirectional.bottomStart,
|
|
||||||
padding: expandedTitlePadding(),
|
|
||||||
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 {
|
mixin _ScrollUnderFlexibleConfig {
|
||||||
TextStyle? get collapsedTextStyle;
|
TextStyle? get collapsedTextStyle;
|
||||||
TextStyle? get expandedTextStyle;
|
TextStyle? get expandedTextStyle;
|
||||||
EdgeInsetsGeometry? get expandedTitlePadding;
|
EdgeInsetsGeometry get expandedTitlePadding;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hand coded defaults based on Material Design 2.
|
// Hand coded defaults based on Material Design 2.
|
||||||
@ -2298,7 +2397,7 @@ class _MediumScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
|||||||
_textTheme.headlineSmall?.apply(color: _colors.onSurface);
|
_textTheme.headlineSmall?.apply(color: _colors.onSurface);
|
||||||
|
|
||||||
@override
|
@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 {
|
class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
||||||
@ -2321,7 +2420,7 @@ class _LargeScrollUnderFlexibleConfig with _ScrollUnderFlexibleConfig {
|
|||||||
_textTheme.headlineMedium?.apply(color: _colors.onSurface);
|
_textTheme.headlineMedium?.apply(color: _colors.onSurface);
|
||||||
|
|
||||||
@override
|
@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
|
// END GENERATED TOKEN PROPERTIES - AppBar
|
||||||
|
@ -2215,7 +2215,7 @@ class _ChipDefaultsM3 extends ChipThemeData {
|
|||||||
EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0);
|
EdgeInsetsGeometry? get padding => const EdgeInsets.all(8.0);
|
||||||
|
|
||||||
/// The chip at text scale 1 starts with 8px on each side and as text scaling
|
/// 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
|
/// Once the widget has a text scaling of 2 or higher than the label padding
|
||||||
/// remains 4px.
|
/// remains 4px.
|
||||||
@override
|
@override
|
||||||
|
@ -62,6 +62,15 @@ TextStyle? iconStyle(WidgetTester tester, IconData icon) {
|
|||||||
return iconRichText.text.style;
|
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 appBarHeight(WidgetTester tester) => tester.getSize(find.byType(AppBar, skipOffstage: false)).height;
|
||||||
double appBarTop(WidgetTester tester) => tester.getTopLeft(find.byType(AppBar, skipOffstage: false)).dy;
|
double appBarTop(WidgetTester tester) => tester.getTopLeft(find.byType(AppBar, skipOffstage: false)).dy;
|
||||||
double appBarBottom(WidgetTester tester) => tester.getBottomLeft(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.
|
// Test the expanded title is positioned correctly.
|
||||||
final Offset titleOffset = tester.getBottomLeft(expandedTitle);
|
final Offset titleOffset = tester.getBottomLeft(expandedTitle);
|
||||||
expect(titleOffset.dx, 16.0);
|
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.
|
// Test the expanded title default color.
|
||||||
expect(
|
expect(
|
||||||
@ -1223,8 +1234,14 @@ void main() {
|
|||||||
// Test the expanded title is positioned correctly.
|
// Test the expanded title is positioned correctly.
|
||||||
final Offset titleOffset = tester.getBottomLeft(expandedTitle);
|
final Offset titleOffset = tester.getBottomLeft(expandedTitle);
|
||||||
expect(titleOffset.dx, 16.0);
|
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.
|
// Test the expanded title default color.
|
||||||
expect(
|
expect(
|
||||||
@ -4704,13 +4721,16 @@ void main() {
|
|||||||
await tester.pumpWidget(buildAppBar());
|
await tester.pumpWidget(buildAppBar());
|
||||||
|
|
||||||
final Finder expandedTitle = find.text(title).first;
|
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));
|
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));
|
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 {
|
testWidgets('SliverAppBar.large expanded title has upper limit on text scaling', (WidgetTester tester) async {
|
||||||
@ -4787,24 +4807,16 @@ void main() {
|
|||||||
await tester.pumpWidget(buildAppBar());
|
await tester.pumpWidget(buildAppBar());
|
||||||
|
|
||||||
final Finder expandedTitle = find.text(title).first;
|
final Finder expandedTitle = find.text(title).first;
|
||||||
Offset titleTop = tester.getTopLeft(expandedTitle);
|
expect(tester.getBottomLeft(expandedTitle).dy, 96.0);
|
||||||
expect(titleTop.dy, 64.0);
|
_verifyTextNotClipped(expandedTitle, tester);
|
||||||
Offset titleBottom = tester.getBottomLeft(expandedTitle);
|
|
||||||
expect(titleBottom.dy, closeTo(96.0, 0.1));
|
|
||||||
|
|
||||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 2.0));
|
await tester.pumpWidget(buildAppBar(textScaleFactor: 2.0));
|
||||||
|
expect(tester.getBottomLeft(expandedTitle).dy, 107.0);
|
||||||
titleTop = tester.getTopLeft(expandedTitle);
|
_verifyTextNotClipped(expandedTitle, tester);
|
||||||
expect(titleTop.dy, closeTo(57.0, 0.1));
|
|
||||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
|
||||||
expect(titleBottom.dy, closeTo(100.0, 0.1));
|
|
||||||
|
|
||||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0));
|
await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0));
|
||||||
|
expect(tester.getBottomLeft(expandedTitle).dy, 107.0);
|
||||||
titleTop = tester.getTopLeft(expandedTitle);
|
_verifyTextNotClipped(expandedTitle, tester);
|
||||||
expect(titleTop.dy, closeTo(57.0, 0.1));
|
|
||||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
|
||||||
expect(titleBottom.dy, closeTo(100.0, 0.1));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('SliverAppBar.large expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async {
|
testWidgets('SliverAppBar.large expanded title position is adjusted with textScaleFactor', (WidgetTester tester) async {
|
||||||
@ -4834,29 +4846,28 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await tester.pumpWidget(buildAppBar());
|
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;
|
final Finder expandedTitle = find.text(title).first;
|
||||||
Offset titleTop = tester.getTopLeft(expandedTitle);
|
final RenderSliver renderSliverAppBar = tester.renderObject(find.byType(SliverAppBar));
|
||||||
expect(titleTop.dy, closeTo(hasIssue99933 ? 91.0 : 92.0, 0.1));
|
expect(
|
||||||
Offset titleBottom = tester.getBottomLeft(expandedTitle);
|
tester.getBottomLeft(expandedTitle).dy,
|
||||||
expect(titleBottom.dy, closeTo(128.0, 0.1));
|
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));
|
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);
|
// The bottom padding of the expanded title needs to be reduced for it to be
|
||||||
expect(titleTop.dy, closeTo(86.1, 0.1));
|
// fully visible.
|
||||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
|
||||||
expect(titleBottom.dy, closeTo(134.1, 0.1));
|
|
||||||
|
|
||||||
await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0));
|
await tester.pumpWidget(buildAppBar(textScaleFactor: 3.0));
|
||||||
|
expect(tester.getBottomLeft(expandedTitle).dy, 124.0);
|
||||||
titleTop = tester.getTopLeft(expandedTitle);
|
_verifyTextNotClipped(expandedTitle, tester);
|
||||||
expect(titleTop.dy, closeTo(86.1, 0.1));
|
|
||||||
titleBottom = tester.getBottomLeft(expandedTitle);
|
|
||||||
expect(titleBottom.dy, closeTo(134.1, 0.1));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
group('AppBar.forceMaterialTransparency', () {
|
group('AppBar.forceMaterialTransparency', () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user