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:
parent
02400772ce
commit
f2be9bcad5
@ -442,6 +442,7 @@ class _IndicatorPainter extends CustomPainter {
|
|||||||
this.dividerColor,
|
this.dividerColor,
|
||||||
this.dividerHeight,
|
this.dividerHeight,
|
||||||
required this.showDivider,
|
required this.showDivider,
|
||||||
|
this.devicePixelRatio,
|
||||||
}) : super(repaint: controller.animation) {
|
}) : super(repaint: controller.animation) {
|
||||||
// TODO(polina-c): stop duplicating code across disposables
|
// TODO(polina-c): stop duplicating code across disposables
|
||||||
// https://github.com/flutter/flutter/issues/137435
|
// https://github.com/flutter/flutter/issues/137435
|
||||||
@ -466,6 +467,7 @@ class _IndicatorPainter extends CustomPainter {
|
|||||||
final Color? dividerColor;
|
final Color? dividerColor;
|
||||||
final double? dividerHeight;
|
final double? dividerHeight;
|
||||||
final bool showDivider;
|
final bool showDivider;
|
||||||
|
final double? devicePixelRatio;
|
||||||
|
|
||||||
// _currentTabOffsets and _currentTextDirection are set each time TabBar
|
// _currentTabOffsets and _currentTextDirection are set each time TabBar
|
||||||
// layout is completed. These values can be null when TabBar contains no
|
// layout is completed. These values can be null when TabBar contains no
|
||||||
@ -562,6 +564,7 @@ class _IndicatorPainter extends CustomPainter {
|
|||||||
final ImageConfiguration configuration = ImageConfiguration(
|
final ImageConfiguration configuration = ImageConfiguration(
|
||||||
size: _currentRect!.size,
|
size: _currentRect!.size,
|
||||||
textDirection: _currentTextDirection,
|
textDirection: _currentTextDirection,
|
||||||
|
devicePixelRatio: devicePixelRatio,
|
||||||
);
|
);
|
||||||
if (showDivider && dividerHeight !> 0) {
|
if (showDivider && dividerHeight !> 0) {
|
||||||
final Paint dividerPaint = Paint()..color = dividerColor!..strokeWidth = dividerHeight!;
|
final Paint dividerPaint = Paint()..color = dividerColor!..strokeWidth = dividerHeight!;
|
||||||
@ -1433,6 +1436,7 @@ class _TabBarState extends State<TabBar> {
|
|||||||
dividerColor: widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor,
|
dividerColor: widget.dividerColor ?? tabBarTheme.dividerColor ?? _defaults.dividerColor,
|
||||||
dividerHeight: widget.dividerHeight ?? tabBarTheme.dividerHeight ?? _defaults.dividerHeight,
|
dividerHeight: widget.dividerHeight ?? tabBarTheme.dividerHeight ?? _defaults.dividerHeight,
|
||||||
showDivider: theme.useMaterial3 && !widget.isScrollable,
|
showDivider: theme.useMaterial3 && !widget.isScrollable,
|
||||||
|
devicePixelRatio: MediaQuery.devicePixelRatioOf(context),
|
||||||
);
|
);
|
||||||
|
|
||||||
oldPainter?.dispose();
|
oldPainter?.dispose();
|
||||||
|
@ -50,6 +50,7 @@ Widget buildFrame({
|
|||||||
TextDirection textDirection = TextDirection.ltr,
|
TextDirection textDirection = TextDirection.ltr,
|
||||||
TabAlignment? tabAlignment,
|
TabAlignment? tabAlignment,
|
||||||
TabBarTheme? tabBarTheme,
|
TabBarTheme? tabBarTheme,
|
||||||
|
Decoration? indicator,
|
||||||
bool? useMaterial3,
|
bool? useMaterial3,
|
||||||
}) {
|
}) {
|
||||||
if (secondaryTabBar) {
|
if (secondaryTabBar) {
|
||||||
@ -88,6 +89,7 @@ Widget buildFrame({
|
|||||||
indicatorColor: indicatorColor,
|
indicatorColor: indicatorColor,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
tabAlignment: tabAlignment,
|
tabAlignment: tabAlignment,
|
||||||
|
indicator: indicator,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -7075,4 +7077,50 @@ void main() {
|
|||||||
expect(find.text('View 0'), findsNothing);
|
expect(find.text('View 0'), findsNothing);
|
||||||
expect(find.text('View 2'), findsOneWidget);
|
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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
@ -228,3 +228,24 @@ class _TabAlwaysKeepAliveWidgetState extends State<TabAlwaysKeepAliveWidget> wit
|
|||||||
return Text(TabAlwaysKeepAliveWidget.text);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user