Commit 8fdd2066 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

DefaultTextStyle.merge and IconTheme.merge improvements (#9358)

I can't figure out if this is genius or a giant hack.

This lets you use DefaultTextStyle.merge and IconTheme.merge without
specifying a BuildContext. It automatically merges in at the
appropriate place in the tree using a Builder widget.
parent aaa0a1cf
......@@ -248,8 +248,7 @@ class CardCollectionState extends State<CardCollection> {
controller: cardModel.textController,
),
)
: new DefaultTextStyle.merge(
context: context,
: DefaultTextStyle.merge(
style: cardLabelStyle.copyWith(
fontSize: _varyFontSizes ? 5.0 + index : null
),
......
......@@ -438,8 +438,7 @@ class _AppBarState extends State<AppBar> {
Widget appBar = new ClipRect(
child: new CustomSingleChildLayout(
delegate: const _ToolbarContainerLayout(),
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: appBarIconTheme,
child: new DefaultTextStyle(
style: sideStyle,
......
......@@ -347,8 +347,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
alignment: FractionalOffset.bottomCenter,
child: new Container(
margin: const EdgeInsets.only(bottom: 10.0),
child: new DefaultTextStyle.merge(
context: context,
child: DefaultTextStyle.merge(
style: new TextStyle(
fontSize: 14.0,
color: colorTween.evaluate(_animations[i]),
......@@ -419,8 +418,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
margin: const EdgeInsets.only(bottom: 10.0),
child: new FadeTransition(
opacity: _animations[i],
child: new DefaultTextStyle.merge(
context: context,
child: DefaultTextStyle.merge(
style: const TextStyle(
fontSize: 14.0,
color: Colors.white
......
......@@ -292,8 +292,7 @@ class _MaterialButtonState extends State<MaterialButton> {
final double height = widget.height ?? buttonTheme.height;
final int elevation = (_highlight ? widget.highlightElevation : widget.elevation) ?? 0;
final bool hasColorOrElevation = (widget.color != null || elevation > 0);
Widget contents = new IconTheme.merge(
context: context,
Widget contents = IconTheme.merge(
data: new IconThemeData(
color: textColor
),
......
......@@ -466,8 +466,7 @@ class DataTable extends StatelessWidget {
? (placeholder ? Colors.black38 : Colors.black87)
: (placeholder ? Colors.white30 : Colors.white70)
),
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: new IconThemeData(
color: isLightTheme ? Colors.black54 : Colors.white70
),
......
......@@ -124,8 +124,7 @@ class _FloatingActionButtonState extends State<FloatingActionButton> {
}
Widget result = new Center(
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: new IconThemeData(color: iconColor),
child: widget.child
)
......
......@@ -124,8 +124,7 @@ class GridTileBar extends StatelessWidget {
height: (title != null && subtitle != null) ? 68.0 : 48.0,
child: new Theme(
data: darkTheme,
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: const IconThemeData(color: Colors.white),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
......
......@@ -151,8 +151,7 @@ class IconButton extends StatelessWidget {
width: iconSize,
child: new Align(
alignment: alignment,
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: new IconThemeData(
size: iconSize,
color: currentColor
......
......@@ -28,17 +28,20 @@ class IconTheme extends InheritedWidget {
/// Creates an icon theme that controls the color, opacity, and size of
/// descendant widgets, and merges in the current icon theme, if any.
///
/// The [context], [data], and [child] arguments must not be null.
factory IconTheme.merge({
/// The [data] and [child] arguments must not be null.
static Widget merge({
Key key,
@required BuildContext context,
@required IconThemeData data,
@required Widget child
}) {
return new IconTheme(
key: key,
data: _getInheritedIconThemeData(context).merge(data),
child: child
return new Builder(
builder: (BuildContext context) {
return new IconTheme(
key: key,
data: _getInheritedIconThemeData(context).merge(data),
child: child,
);
},
);
}
......
......@@ -439,8 +439,7 @@ class InputDecorator extends StatelessWidget {
new Container(
margin: new EdgeInsets.only(top: iconTop),
width: isDense ? 40.0 : 48.0,
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: new IconThemeData(
color: isFocused ? activeColor : Colors.black45,
size: isDense ? 18.0 : 24.0,
......
......@@ -345,8 +345,7 @@ class ListTile extends StatelessWidget {
final List<Widget> children = <Widget>[];
if (leading != null) {
children.add(new IconTheme.merge(
context: context,
children.add(IconTheme.merge(
data: new IconThemeData(color: _iconColor(theme, tileTheme)),
child: new Container(
margin: const EdgeInsets.only(right: 16.0),
......
......@@ -377,8 +377,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
// See https://material.google.com/components/data-tables.html#data-tables-tables-within-cards
style: _selectedRowCount > 0 ? themeData.textTheme.subhead.copyWith(color: themeData.accentColor)
: themeData.textTheme.title.copyWith(fontWeight: FontWeight.w400),
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: const IconThemeData(
opacity: 0.54
),
......@@ -413,8 +412,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
),
new DefaultTextStyle(
style: footerTextStyle,
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: const IconThemeData(
opacity: 0.54
),
......
......@@ -160,8 +160,7 @@ class _PopupMenuItemState<T extends PopupMenuItem<dynamic>> extends State<T> {
);
if (!widget.enabled) {
final bool isDark = theme.brightness == Brightness.dark;
item = new IconTheme.merge(
context: context,
item = IconTheme.merge(
data: new IconThemeData(opacity: isDark ? 0.5 : 0.38),
child: item
);
......
......@@ -138,8 +138,7 @@ class _TabStyle extends AnimatedWidget {
return new DefaultTextStyle(
style: textStyle.copyWith(color: color),
child: new IconTheme.merge(
context: context,
child: IconTheme.merge(
data: new IconThemeData(
size: 24.0,
color: color,
......
......@@ -201,8 +201,7 @@ class _TwoLevelSublistState extends State<TwoLevelSublist> with SingleTickerProv
),
child: new Column(
children: <Widget>[
new IconTheme.merge(
context: context,
IconTheme.merge(
data: new IconThemeData(color: _iconColor.evaluate(_easeInAnimation)),
child: new TwoLevelListItem(
onTap: _handleOnTap,
......
......@@ -41,15 +41,15 @@ class DefaultTextStyle extends InheritedWidget {
maxLines = null,
overflow = TextOverflow.clip;
/// Creates a default text style that inherits from the given [BuildContext].
/// Creates a default text style that overrides the text styles in scope at
/// this point in the widget tree.
///
/// The given [style] is merged with the [style] from the default text style
/// for the given [BuildContext] and, if non-null, the given [textAlign]
/// replaces the [textAlign] from the default text style for the given
/// [BuildContext].
factory DefaultTextStyle.merge({
/// for the [BuildContext] where the widget is inserted, and any of the other
/// arguments that are not null replace the corresponding properties on that
/// same default text style.
static Widget merge({
Key key,
@required BuildContext context,
TextStyle style,
TextAlign textAlign,
bool softWrap,
......@@ -57,17 +57,20 @@ class DefaultTextStyle extends InheritedWidget {
int maxLines,
@required Widget child,
}) {
assert(context != null);
assert(child != null);
final DefaultTextStyle parent = DefaultTextStyle.of(context);
return new DefaultTextStyle(
key: key,
style: parent.style.merge(style),
textAlign: textAlign ?? parent.textAlign,
softWrap: softWrap ?? parent.softWrap,
overflow: overflow ?? parent.overflow,
maxLines: maxLines ?? parent.maxLines,
child: child
return new Builder(
builder: (BuildContext context) {
final DefaultTextStyle parent = DefaultTextStyle.of(context);
return new DefaultTextStyle(
key: key,
style: parent.style.merge(style),
textAlign: textAlign ?? parent.textAlign,
softWrap: softWrap ?? parent.softWrap,
overflow: overflow ?? parent.overflow,
maxLines: maxLines ?? parent.maxLines,
child: child
);
},
);
}
......
......@@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
void main() {
testWidgets('Navigator.push works within a PopupMenuButton', (WidgetTester tester) async {
final Key targetKey = new UniqueKey();
await tester.pumpWidget(
new MaterialApp(
routes: <String, WidgetBuilder> {
......@@ -17,6 +18,7 @@ void main() {
home: new Material(
child: new Center(
child: new Builder(
key: targetKey,
builder: (BuildContext context) {
return new PopupMenuButton<int>(
onSelected: (int value) {
......@@ -38,7 +40,7 @@ void main() {
)
);
await tester.tap(find.byType(Builder));
await tester.tap(find.byKey(targetKey));
await tester.pump();
await tester.pump(const Duration(seconds: 1)); // finish the menu animation
......
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