Introduce TabBar.textScaler
for tab label upper text scale limit (#147232)
fixes [Tab is hardcoding the height of the icons and the text ](https://github.com/flutter/flutter/issues/13322) ### Description This PR introduces `TabBar.textScaler` to provide upper text scale limit for tab label. ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, home: MediaQuery( data: const MediaQueryData(textScaler: TextScaler.linear(3.0)), child: DefaultTabController( length: 3, child: Scaffold( appBar: AppBar( title: const Text('Sample'), bottom: const TabBar( textScaler: TextScaler.linear(2.0), tabs: <Widget>[ Tab(text: 'Tab 1'), Tab(text: 'Tab 2'), Tab(text: 'Tab 3'), ], ), ), floatingActionButton: Builder(builder: (BuildContext context) { return FloatingActionButton( onPressed: () { print(MediaQuery.textScalerOf(context)); }, child: const Icon(Icons.add), ); }), ), ), ), ); } } ``` </details> ### Without `TabBar.textScaler`  ### With `TabBar.textScaler` ```dart bottom: const TabBar( textScaler: TextScaler.linear(2.0), tabs: <Widget>[ Tab(text: 'Tab 1'), Tab(text: 'Tab 2'), Tab(text: 'Tab 3'), ], ), ``` 
This commit is contained in:
parent
8796562d0a
commit
74356f30dd
@ -42,6 +42,7 @@ class TabBarTheme with Diagnosticable {
|
||||
this.splashFactory,
|
||||
this.mouseCursor,
|
||||
this.tabAlignment,
|
||||
this.textScaler,
|
||||
});
|
||||
|
||||
/// Overrides the default value for [TabBar.indicator].
|
||||
@ -98,6 +99,9 @@ class TabBarTheme with Diagnosticable {
|
||||
/// Overrides the default value for [TabBar.tabAlignment].
|
||||
final TabAlignment? tabAlignment;
|
||||
|
||||
/// Overrides the default value for [TabBar.textScaler].
|
||||
final TextScaler? textScaler;
|
||||
|
||||
/// Creates a copy of this object but with the given fields replaced with the
|
||||
/// new values.
|
||||
TabBarTheme copyWith({
|
||||
@ -115,6 +119,7 @@ class TabBarTheme with Diagnosticable {
|
||||
InteractiveInkFeatureFactory? splashFactory,
|
||||
MaterialStateProperty<MouseCursor?>? mouseCursor,
|
||||
TabAlignment? tabAlignment,
|
||||
TextScaler? textScaler,
|
||||
}) {
|
||||
return TabBarTheme(
|
||||
indicator: indicator ?? this.indicator,
|
||||
@ -131,6 +136,7 @@ class TabBarTheme with Diagnosticable {
|
||||
splashFactory: splashFactory ?? this.splashFactory,
|
||||
mouseCursor: mouseCursor ?? this.mouseCursor,
|
||||
tabAlignment: tabAlignment ?? this.tabAlignment,
|
||||
textScaler: textScaler ?? this.textScaler,
|
||||
);
|
||||
}
|
||||
|
||||
@ -161,6 +167,7 @@ class TabBarTheme with Diagnosticable {
|
||||
splashFactory: t < 0.5 ? a.splashFactory : b.splashFactory,
|
||||
mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
|
||||
tabAlignment: t < 0.5 ? a.tabAlignment : b.tabAlignment,
|
||||
textScaler: t < 0.5 ? a.textScaler : b.textScaler,
|
||||
);
|
||||
}
|
||||
|
||||
@ -180,6 +187,7 @@ class TabBarTheme with Diagnosticable {
|
||||
splashFactory,
|
||||
mouseCursor,
|
||||
tabAlignment,
|
||||
textScaler,
|
||||
);
|
||||
|
||||
@override
|
||||
@ -204,6 +212,7 @@ class TabBarTheme with Diagnosticable {
|
||||
&& other.overlayColor == overlayColor
|
||||
&& other.splashFactory == splashFactory
|
||||
&& other.mouseCursor == mouseCursor
|
||||
&& other.tabAlignment == tabAlignment;
|
||||
&& other.tabAlignment == tabAlignment
|
||||
&& other.textScaler == textScaler;
|
||||
}
|
||||
}
|
||||
|
@ -864,6 +864,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.splashFactory,
|
||||
this.splashBorderRadius,
|
||||
this.tabAlignment,
|
||||
this.textScaler,
|
||||
}) : _isPrimary = true,
|
||||
assert(indicator != null || (indicatorWeight > 0.0));
|
||||
|
||||
@ -915,6 +916,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.splashFactory,
|
||||
this.splashBorderRadius,
|
||||
this.tabAlignment,
|
||||
this.textScaler,
|
||||
}) : _isPrimary = false,
|
||||
assert(indicator != null || (indicatorWeight > 0.0));
|
||||
|
||||
@ -1246,6 +1248,16 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
/// otherwise [TabAlignment.fill] is used.
|
||||
final TabAlignment? tabAlignment;
|
||||
|
||||
/// Specifies the text scaling behavior for the [Tab] label.
|
||||
///
|
||||
/// If this is null, then the value of [TabBarTheme.textScaler] is used. If that is
|
||||
/// also null, then the text scaling behavior is determined by the [MediaQueryData.textScaler]
|
||||
/// from the ambient [MediaQuery], or 1.0 if there is no [MediaQuery] in scope.
|
||||
///
|
||||
/// See also:
|
||||
/// * [TextScaler], which is used to scale text based on the device's text scale factor.
|
||||
final TextScaler? textScaler;
|
||||
|
||||
/// A size whose height depends on if the tabs have both icons and text.
|
||||
///
|
||||
/// [AppBar] uses this size to compute its own preferred size.
|
||||
@ -1828,7 +1840,10 @@ class _TabBarState extends State<TabBar> {
|
||||
);
|
||||
}
|
||||
|
||||
return tabBar;
|
||||
return MediaQuery(
|
||||
data: MediaQuery.of(context).copyWith(textScaler: widget.textScaler ?? tabBarTheme.textScaler),
|
||||
child: tabBar,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
@Tags(<String>['reduced-test-set'])
|
||||
library;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@ -1539,4 +1540,48 @@ void main() {
|
||||
expect(selectedTextStyle.color, selectedColor);
|
||||
expect(unselectedTextStyle.color, unselectedColor);
|
||||
});
|
||||
|
||||
testWidgets('TabBarTheme.textScaler overrides tab label text scale, textScaleFactor = noScaling, 1.75, 2.0', (WidgetTester tester) async {
|
||||
final List<String> tabs = <String>['Tab 1', 'Tab 2'];
|
||||
|
||||
Widget buildTabs({ TextScaler? textScaler }) {
|
||||
return MaterialApp(
|
||||
theme: ThemeData(
|
||||
tabBarTheme: TabBarTheme(
|
||||
textScaler: textScaler,
|
||||
),
|
||||
),
|
||||
home: MediaQuery(
|
||||
data: const MediaQueryData(textScaler: TextScaler.linear(3.0)),
|
||||
child: DefaultTabController(
|
||||
length: tabs.length,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
bottom: TabBar(
|
||||
tabs: tabs.map((String tab) => Tab(text: tab)).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildTabs(textScaler: TextScaler.noScaling));
|
||||
|
||||
Size labelSize = tester.getSize(find.text('Tab 1'));
|
||||
expect(labelSize, equals(const Size(70.5, 20.0)));
|
||||
|
||||
await tester.pumpWidget(buildTabs(textScaler: const TextScaler.linear(1.75)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
labelSize = tester.getSize(find.text('Tab 1'));
|
||||
expect(labelSize, equals(const Size(123.0, 35.0)));
|
||||
|
||||
await tester.pumpWidget(buildTabs(textScaler: const TextScaler.linear(2.0)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
labelSize = tester.getSize(find.text('Tab 1'));
|
||||
expect(labelSize, equals(const Size(140.5, 40.0)));
|
||||
}, skip: isBrowser && !isSkiaWeb); // https://github.com/flutter/flutter/issues/87543
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
@ -7119,4 +7120,42 @@ void main() {
|
||||
expect(config.textDirection, TextDirection.rtl);
|
||||
expect(config.devicePixelRatio, 2.33);
|
||||
});
|
||||
|
||||
testWidgets('TabBar.textScaler overrides tab label text scale, textScaleFactor = noScaling, 1.75, 2.0', (WidgetTester tester) async {
|
||||
final List<String> tabs = <String>['Tab 1', 'Tab 2'];
|
||||
|
||||
Widget buildTabs({ TextScaler? textScaler }) {
|
||||
return MaterialApp(
|
||||
home: MediaQuery(
|
||||
data: const MediaQueryData(textScaler: TextScaler.linear(3.0)),
|
||||
child: DefaultTabController(
|
||||
length: tabs.length,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
bottom: TabBar(
|
||||
textScaler: textScaler,
|
||||
tabs: tabs.map((String tab) => Tab(text: tab)).toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildTabs(textScaler: TextScaler.noScaling));
|
||||
|
||||
Size labelSize = tester.getSize(find.text('Tab 1'));
|
||||
expect(labelSize, equals(const Size(70.5, 20.0)));
|
||||
|
||||
await tester.pumpWidget(buildTabs(textScaler: const TextScaler.linear(1.75)));
|
||||
|
||||
labelSize = tester.getSize(find.text('Tab 1'));
|
||||
expect(labelSize, equals(const Size(123.0, 35.0)));
|
||||
|
||||
await tester.pumpWidget(buildTabs(textScaler: const TextScaler.linear(2.0)));
|
||||
|
||||
labelSize = tester.getSize(find.text('Tab 1'));
|
||||
expect(labelSize, equals(const Size(140.5, 40.0)));
|
||||
}, skip: isBrowser && !isSkiaWeb); // https://github.com/flutter/flutter/issues/87543
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user