Commit 9baca001 authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Make Tab take a widget as child (#12613)

* Make Tab take a widget as child

This way you can override the semantics information of a Tab (see test).

Fixes https://github.com/flutter/flutter/issues/12432

* more tests

* review comments

* review comment

* doc nits

* style fix
parent af0afff1
......@@ -34,23 +34,35 @@ const double _kMaxTabWidth = 264.0;
/// * [TabController], which coordinates tab selection between a [TabBar] and a [TabBarView].
/// * <https://material.google.com/components/tabs.html>
class Tab extends StatelessWidget {
/// Creates a material design [TabBar] tab. At least one of [text] and [icon]
/// must be non-null.
/// Creates a material design [TabBar] tab. At least one of [text], [icon],
/// and [child] must be non-null. The [text] and [child] arguments must not be
/// used at the same time.
const Tab({
Key key,
this.text,
this.icon,
}) : assert(text != null || icon != null),
this.child,
}) : assert(text != null || child != null || icon != null),
assert(!(text != null && null != child)), // TODO(goderbauer): https://github.com/dart-lang/sdk/issues/31140
super(key: key);
/// The text to display as the tab's label.
///
/// Must not be used in combination with [child].
final String text;
/// The widget to be used as the tab's label.
///
/// Usually a [Text] widget, possibly wrapped in a [Semantics] widget.
///
/// Must not be used in combination with [text].
final Widget child;
/// An icon to display as the tab's label.
final Widget icon;
Widget _buildLabelText() {
return new Text(text, softWrap: false, overflow: TextOverflow.fade);
return child ?? new Text(text, softWrap: false, overflow: TextOverflow.fade);
}
@override
......
......@@ -1218,4 +1218,75 @@ void main() {
expect(controller.index, 1);
});
testWidgets('can override semantics of tabs', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
final List<Tab> tabs = new List<Tab>.generate(2, (int index) {
return new Tab(
child: new Semantics(
label: 'Semantics override $index',
child: new ExcludeSemantics(
child: new Text('TAB #$index'),
),
),
);
});
final TabController controller = new TabController(
vsync: const TestVSync(),
length: tabs.length,
initialIndex: 0,
);
await tester.pumpWidget(
boilerplate(
child: new Semantics(
container: true,
child: new TabBar(
isScrollable: true,
controller: controller,
tabs: tabs,
),
),
),
);
final TestSemantics expectedSemantics = new TestSemantics.root(
children: <TestSemantics>[
new TestSemantics.rootChild(
id: 64,
rect: TestSemantics.fullScreen,
children: <TestSemantics>[
new TestSemantics(
id: 65,
actions: SemanticsAction.tap.index,
flags: SemanticsFlags.isSelected.index,
label: 'Semantics override 0\nTab 1 of 2',
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
transform: new Matrix4.translationValues(0.0, 276.0, 0.0),
),
new TestSemantics(
id: 68,
actions: SemanticsAction.tap.index,
label: 'Semantics override 1\nTab 2 of 2',
rect: new Rect.fromLTRB(0.0, 0.0, 108.0, kTextTabBarHeight),
transform: new Matrix4.translationValues(108.0, 276.0, 0.0),
),
],
),
],
);
expect(semantics, hasSemantics(expectedSemantics));
semantics.dispose();
});
test('illegal constructor combinations', () {
final Widget $null = null;
expect(() => new Tab(icon: $null), throwsAssertionError);
expect(() => new Tab(icon: new Container(), text: 'foo', child: new Container()), throwsAssertionError);
expect(() => new Tab(text: 'foo', child: new Container()), throwsAssertionError);
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment