Fix Tab indicator image configuration doesn't inherit device pixel ratio (#146812)

fixes [The image for the indicator of the TabBar does not auto-adapt to different resolutions](https://github.com/flutter/flutter/issues/145204)

### Description
This PR provides device pixel ratio to the tab indicator painter.
This commit is contained in:
Taha Tesser 2024-04-17 10:59:07 +03:00 committed by GitHub
parent 02400772ce
commit f2be9bcad5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 73 additions and 0 deletions

View file

@ -442,6 +442,7 @@ class _IndicatorPainter extends CustomPainter {
this.dividerColor,
this.dividerHeight,
required this.showDivider,
this.devicePixelRatio,
}) : super(repaint: controller.animation) {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
@ -466,6 +467,7 @@ class _IndicatorPainter extends CustomPainter {
final Color? dividerColor;
final double? dividerHeight;
final bool showDivider;
final double? devicePixelRatio;
// _currentTabOffsets and _currentTextDirection are set each time TabBar
// layout is completed. These values can be null when TabBar contains no
@ -562,6 +564,7 @@ class _IndicatorPainter extends CustomPainter {
final ImageConfiguration configuration = ImageConfiguration(
size: _currentRect!.size,
textDirection: _currentTextDirection,
devicePixelRatio: devicePixelRatio,
);
if (showDivider && dividerHeight !> 0) {
final Paint dividerPaint = Paint()..color = dividerColor!..strokeWidth = dividerHeight!;
@ -1433,6 +1436,7 @@ class _TabBarState extends State<TabBar> {
dividerColor: widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor,
dividerHeight: widget.dividerHeight ?? tabBarTheme.dividerHeight ?? _defaults.dividerHeight,
showDivider: theme.useMaterial3 && !widget.isScrollable,
devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
);
oldPainter?.dispose();

View file

@ -50,6 +50,7 @@ Widget buildFrame({
TextDirection textDirection = TextDirection.ltr,
TabAlignment? tabAlignment,
TabBarTheme? tabBarTheme,
Decoration? indicator,
bool? useMaterial3,
}) {
if (secondaryTabBar) {
@ -88,6 +89,7 @@ Widget buildFrame({
indicatorColor: indicatorColor,
padding: padding,
tabAlignment: tabAlignment,
indicator: indicator,
),
),
);
@ -7075,4 +7077,50 @@ void main() {
expect(find.text('View 0'), findsNothing);
expect(find.text('View 2'), findsOneWidget);
});
testWidgets('Tab indicator painter image configuration', (WidgetTester tester) async {
final List<String> tabs = <String>['A', 'B'];
final TestIndicatorDecoration decoration = TestIndicatorDecoration();
Widget buildTabs({
TextDirection textDirection = TextDirection.ltr,
double ratio = 1.0,
}) {
return MaterialApp(
home: MediaQuery(
data: MediaQueryData(devicePixelRatio: ratio),
child: Directionality(
textDirection: textDirection,
child: DefaultTabController(
length: tabs.length,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
indicator: decoration,
tabs: tabs.map((String tab) => Tab(text: tab)).toList(),
),
),
),
),
),
),
);
}
await tester.pumpWidget(buildTabs());
ImageConfiguration config = decoration.painters.last.lastConfiguration!;
expect(config.size?.width, closeTo(14.1, 0.1));
expect(config.size?.height, equals(48.0));
expect(config.textDirection, TextDirection.ltr);
expect(config.devicePixelRatio, 1.0);
await tester.pumpWidget(buildTabs(textDirection: TextDirection.rtl, ratio: 2.33));
config = decoration.painters.last.lastConfiguration!;
expect(config.size?.width, closeTo(14.1, 0.1));
expect(config.size?.height, equals(48.0));
expect(config.textDirection, TextDirection.rtl);
expect(config.devicePixelRatio, 2.33);
});
}

View file

@ -228,3 +228,24 @@ class _TabAlwaysKeepAliveWidgetState extends State<TabAlwaysKeepAliveWidget> wit
return Text(TabAlwaysKeepAliveWidget.text);
}
}
// This decoration is used to test the indicator decoration image configuration.
class TestIndicatorDecoration extends Decoration {
final List<TestIndicatorBoxPainter> painters = <TestIndicatorBoxPainter>[];
@override
BoxPainter createBoxPainter([VoidCallback? onChanged]) {
final TestIndicatorBoxPainter painter = TestIndicatorBoxPainter();
painters.add(painter);
return painter;
}
}
class TestIndicatorBoxPainter extends BoxPainter {
ImageConfiguration? lastConfiguration;
@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
lastConfiguration = configuration;
}
}