Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
2e01eef5
Unverified
Commit
2e01eef5
authored
Aug 21, 2019
by
Hans Muller
Committed by
GitHub
Aug 21, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added InheritedTheme (#38583)
parent
4277f364
Changes
17
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1147 additions
and
18 deletions
+1147
-18
banner_theme.dart
packages/flutter/lib/src/material/banner_theme.dart
+7
-1
button_theme.dart
packages/flutter/lib/src/material/button_theme.dart
+7
-1
chip_theme.dart
packages/flutter/lib/src/material/chip_theme.dart
+7
-1
divider_theme.dart
packages/flutter/lib/src/material/divider_theme.dart
+7
-1
list_tile.dart
packages/flutter/lib/src/material/list_tile.dart
+15
-1
popup_menu.dart
packages/flutter/lib/src/material/popup_menu.dart
+26
-5
popup_menu_theme.dart
packages/flutter/lib/src/material/popup_menu_theme.dart
+7
-1
slider_theme.dart
packages/flutter/lib/src/material/slider_theme.dart
+7
-2
theme.dart
packages/flutter/lib/src/material/theme.dart
+7
-1
toggle_buttons_theme.dart
packages/flutter/lib/src/material/toggle_buttons_theme.dart
+7
-1
tooltip_theme.dart
packages/flutter/lib/src/material/tooltip_theme.dart
+7
-1
icon_theme.dart
packages/flutter/lib/src/widgets/icon_theme.dart
+8
-1
inherited_theme.dart
packages/flutter/lib/src/widgets/inherited_theme.dart
+146
-0
text.dart
packages/flutter/lib/src/widgets/text.dart
+16
-1
widgets.dart
packages/flutter/lib/widgets.dart
+1
-0
inherited_theme_test.dart
packages/flutter/test/material/inherited_theme_test.dart
+723
-0
inherited_theme_test.dart
packages/flutter/test/widgets/inherited_theme_test.dart
+149
-0
No files found.
packages/flutter/lib/src/material/banner_theme.dart
View file @
2e01eef5
...
...
@@ -116,7 +116,7 @@ class MaterialBannerThemeData extends Diagnosticable {
///
/// Values specified here are used for [MaterialBanner] properties that are not
/// given an explicit non-null value.
class
MaterialBannerTheme
extends
Inherited
Widget
{
class
MaterialBannerTheme
extends
Inherited
Theme
{
/// Creates a banner theme that controls the configurations for
/// [MaterialBanner]s in its widget subtree.
const
MaterialBannerTheme
({
...
...
@@ -144,6 +144,12 @@ class MaterialBannerTheme extends InheritedWidget {
return
popupMenuTheme
?.
data
??
Theme
.
of
(
context
).
bannerTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
MaterialBannerTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
MaterialBannerTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
MaterialBannerTheme
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
MaterialBannerTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
packages/flutter/lib/src/material/button_theme.dart
View file @
2e01eef5
...
...
@@ -63,7 +63,7 @@ enum ButtonBarLayoutBehavior {
/// based on the ambient button theme.
/// * [RawMaterialButton], which can be used to configure a button that doesn't
/// depend on any inherited themes.
class
ButtonTheme
extends
Inherited
Widget
{
class
ButtonTheme
extends
Inherited
Theme
{
/// Creates a button theme.
///
/// The [textTheme], [minWidth], [height], and [colorScheme] arguments
...
...
@@ -230,6 +230,12 @@ class ButtonTheme extends InheritedWidget {
return
buttonTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
ButtonTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
ButtonTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
ButtonTheme
.
fromButtonThemeData
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
ButtonTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
...
...
packages/flutter/lib/src/material/chip_theme.dart
View file @
2e01eef5
...
...
@@ -40,7 +40,7 @@ import 'theme_data.dart';
/// theme.
/// * [ThemeData], which describes the overall theme information for the
/// application.
class
ChipTheme
extends
Inherited
Widget
{
class
ChipTheme
extends
Inherited
Theme
{
/// Applies the given theme [data] to [child].
///
/// The [data] and [child] arguments must not be null.
...
...
@@ -89,6 +89,12 @@ class ChipTheme extends InheritedWidget {
return
inheritedTheme
?.
data
??
Theme
.
of
(
context
).
chipTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
ChipTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
ChipTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
ChipTheme
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
ChipTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
...
...
packages/flutter/lib/src/material/divider_theme.dart
View file @
2e01eef5
...
...
@@ -132,7 +132,7 @@ class DividerThemeData extends Diagnosticable {
/// An inherited widget that defines the configuration for
/// [Divider]s, [VerticalDividers]s, dividers between [ListTile]s, and dividers
/// between rows in [DataTable]s in this widget's subtree.
class
DividerTheme
extends
Inherited
Widget
{
class
DividerTheme
extends
Inherited
Theme
{
/// Creates a divider theme that controls the configurations for
/// [Divider]s, [VerticalDividers]s, dividers between [ListTile]s, and dividers
/// between rows in [DataTable]s in its widget subtree.
...
...
@@ -163,6 +163,12 @@ class DividerTheme extends InheritedWidget {
return
dividerTheme
?.
data
??
Theme
.
of
(
context
).
dividerTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
DividerTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
DividerTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
DividerTheme
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
DividerTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
packages/flutter/lib/src/material/list_tile.dart
View file @
2e01eef5
...
...
@@ -36,7 +36,7 @@ enum ListTileStyle {
///
/// The [Drawer] widget specifies a tile theme for its children which sets
/// [style] to [ListTileStyle.drawer].
class
ListTileTheme
extends
Inherited
Widget
{
class
ListTileTheme
extends
Inherited
Theme
{
/// Creates a list tile theme that controls the color and style parameters for
/// [ListTile]s.
const
ListTileTheme
({
...
...
@@ -115,6 +115,20 @@ class ListTileTheme extends InheritedWidget {
return
result
??
const
ListTileTheme
();
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
ListTileTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
ListTileTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
ListTileTheme
(
dense:
dense
,
style:
style
,
selectedColor:
selectedColor
,
iconColor:
iconColor
,
textColor:
textColor
,
contentPadding:
contentPadding
,
child:
child
,
);
}
@override
bool
updateShouldNotify
(
ListTileTheme
oldWidget
)
{
return
dense
!=
oldWidget
.
dense
...
...
packages/flutter/lib/src/material/popup_menu.dart
View file @
2e01eef5
...
...
@@ -264,7 +264,7 @@ class PopupMenuItemState<T, W extends PopupMenuItem<T>> extends State<W> {
duration:
kThemeChangeDuration
,
child:
Baseline
(
baseline:
widget
.
height
-
_kBaselineOffsetFromBottom
,
baselineType:
style
.
textBaseline
,
baselineType:
style
.
textBaseline
??
TextBaseline
.
alphabetic
,
child:
buildChild
(),
),
);
...
...
@@ -608,6 +608,8 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
this
.
semanticLabel
,
this
.
shape
,
this
.
color
,
this
.
showMenuContext
,
this
.
captureInheritedThemes
,
});
final
RelativeRect
position
;
...
...
@@ -619,6 +621,8 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
final
ShapeBorder
shape
;
final
Color
color
;
final
PopupMenuThemeData
popupMenuTheme
;
final
BuildContext
showMenuContext
;
final
bool
captureInheritedThemes
;
@override
Animation
<
double
>
createAnimation
()
{
...
...
@@ -656,10 +660,15 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
}
Widget
menu
=
_PopupMenu
<
T
>(
route:
this
,
semanticLabel:
semanticLabel
);
if
(
popupMenuTheme
!=
null
)
menu
=
PopupMenuTheme
(
data:
PopupMenuThemeData
(
textStyle:
popupMenuTheme
.
textStyle
),
child:
menu
);
if
(
theme
!=
null
)
menu
=
Theme
(
data:
theme
,
child:
menu
);
if
(
captureInheritedThemes
)
{
menu
=
InheritedTheme
.
captureAll
(
showMenuContext
,
menu
);
}
else
{
// For the sake of backwards compatibility. An (unlikely) app that relied
// on having menus only inherit from the material Theme could set
// captureInheritedThemes to false and get the original behvaior.
if
(
theme
!=
null
)
menu
=
Theme
(
data:
theme
,
child:
menu
);
}
return
MediaQuery
.
removePadding
(
context:
context
,
...
...
@@ -743,10 +752,12 @@ Future<T> showMenu<T>({
String
semanticLabel
,
ShapeBorder
shape
,
Color
color
,
bool
captureInheritedThemes
=
true
,
})
{
assert
(
context
!=
null
);
assert
(
position
!=
null
);
assert
(
items
!=
null
&&
items
.
isNotEmpty
);
assert
(
captureInheritedThemes
!=
null
);
assert
(
debugCheckHasMaterialLocalizations
(
context
));
String
label
=
semanticLabel
;
...
...
@@ -770,6 +781,8 @@ Future<T> showMenu<T>({
barrierLabel:
MaterialLocalizations
.
of
(
context
).
modalBarrierDismissLabel
,
shape:
shape
,
color:
color
,
showMenuContext:
context
,
captureInheritedThemes:
captureInheritedThemes
,
));
}
...
...
@@ -862,9 +875,11 @@ class PopupMenuButton<T> extends StatefulWidget {
this
.
enabled
=
true
,
this
.
shape
,
this
.
color
,
this
.
captureInheritedThemes
=
true
,
})
:
assert
(
itemBuilder
!=
null
),
assert
(
offset
!=
null
),
assert
(
enabled
!=
null
),
assert
(
captureInheritedThemes
!=
null
),
assert
(!(
child
!=
null
&&
icon
!=
null
)),
// fails if passed both parameters
super
(
key:
key
);
...
...
@@ -943,6 +958,11 @@ class PopupMenuButton<T> extends StatefulWidget {
/// Theme.of(context).cardColor is used.
final
Color
color
;
/// If true (the default) then the menu will be wrapped with copies
/// of the [InheritedThemes], like [Theme] and [PopupMenuTheme], which
/// are defined above the [BuildContext] where the menu is shown.
final
bool
captureInheritedThemes
;
@override
_PopupMenuButtonState
<
T
>
createState
()
=>
_PopupMenuButtonState
<
T
>();
}
...
...
@@ -970,6 +990,7 @@ class _PopupMenuButtonState<T> extends State<PopupMenuButton<T>> {
position:
position
,
shape:
widget
.
shape
??
popupMenuTheme
.
shape
,
color:
widget
.
color
??
popupMenuTheme
.
color
,
captureInheritedThemes:
widget
.
captureInheritedThemes
,
)
.
then
<
void
>((
T
newValue
)
{
if
(!
mounted
)
...
...
packages/flutter/lib/src/material/popup_menu_theme.dart
View file @
2e01eef5
...
...
@@ -121,7 +121,7 @@ class PopupMenuThemeData extends Diagnosticable {
///
/// Values specified here are used for popup menu properties that are not
/// given an explicit non-null value.
class
PopupMenuTheme
extends
Inherited
Widget
{
class
PopupMenuTheme
extends
Inherited
Theme
{
/// Creates a popup menu theme that controls the configurations for
/// popup menus in its widget subtree.
///
...
...
@@ -149,6 +149,12 @@ class PopupMenuTheme extends InheritedWidget {
return
popupMenuTheme
?.
data
??
Theme
.
of
(
context
).
popupMenuTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
PopupMenuTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
PopupMenuTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
PopupMenuTheme
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
PopupMenuTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
packages/flutter/lib/src/material/slider_theme.dart
View file @
2e01eef5
...
...
@@ -134,7 +134,7 @@ import 'theme_data.dart';
/// {@macro flutter.material.slider.seeAlso.rangeSliderValueIndicatorShape}
/// {@macro flutter.material.slider.seeAlso.rangeSliderTrackShape}
/// {@macro flutter.material.slider.seeAlso.rangeSliderTickMarkShape}
class
SliderTheme
extends
Inherited
Widget
{
class
SliderTheme
extends
Inherited
Theme
{
/// Applies the given theme [data] to [child].
///
/// The [data] and [child] arguments must not be null.
...
...
@@ -189,6 +189,12 @@ class SliderTheme extends InheritedWidget {
return
inheritedTheme
!=
null
?
inheritedTheme
.
data
:
Theme
.
of
(
context
).
sliderTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
SliderTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
SliderTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
SliderTheme
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
SliderTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
...
...
@@ -2928,4 +2934,3 @@ class RangeLabels {
return
'
$runtimeType
(
$start
,
$end
)'
;
}
}
packages/flutter/lib/src/material/theme.dart
View file @
2e01eef5
...
...
@@ -164,7 +164,7 @@ class Theme extends StatelessWidget {
}
}
class
_InheritedTheme
extends
Inherited
Widget
{
class
_InheritedTheme
extends
Inherited
Theme
{
const
_InheritedTheme
({
Key
key
,
@required
this
.
theme
,
...
...
@@ -174,6 +174,12 @@ class _InheritedTheme extends InheritedWidget {
final
Theme
theme
;
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
_InheritedTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
_InheritedTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
Theme
(
data:
theme
.
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
_InheritedTheme
old
)
=>
theme
.
data
!=
old
.
theme
.
data
;
}
...
...
packages/flutter/lib/src/material/toggle_buttons_theme.dart
View file @
2e01eef5
...
...
@@ -227,7 +227,7 @@ class ToggleButtonsThemeData extends Diagnosticable {
///
/// Values specified here are used for [ToggleButtons] properties that are not
/// given an explicit non-null value.
class
ToggleButtonsTheme
extends
Inherited
Widget
{
class
ToggleButtonsTheme
extends
Inherited
Theme
{
/// Creates a toggle buttons theme that controls the color and border
/// parameters for [ToggleButtons].
///
...
...
@@ -256,6 +256,12 @@ class ToggleButtonsTheme extends InheritedWidget {
return
toggleButtonsTheme
?.
data
??
Theme
.
of
(
context
).
toggleButtonsTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
ToggleButtonsTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
ToggleButtonsTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
ToggleButtonsTheme
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
ToggleButtonsTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
packages/flutter/lib/src/material/tooltip_theme.dart
View file @
2e01eef5
...
...
@@ -213,7 +213,7 @@ class TooltipThemeData extends Diagnosticable {
/// ),
/// ```
/// {@end-tool}
class
TooltipTheme
extends
Inherited
Widget
{
class
TooltipTheme
extends
Inherited
Theme
{
/// Creates a tooltip theme that controls the configurations for
/// [Tooltip].
///
...
...
@@ -241,6 +241,12 @@ class TooltipTheme extends InheritedWidget {
return
tooltipTheme
?.
data
??
Theme
.
of
(
context
).
tooltipTheme
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
TooltipTheme
ancestorTheme
=
context
.
ancestorWidgetOfExactType
(
TooltipTheme
);
return
identical
(
this
,
ancestorTheme
)
?
child
:
TooltipTheme
(
data:
data
,
child:
child
);
}
@override
bool
updateShouldNotify
(
TooltipTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
}
packages/flutter/lib/src/widgets/icon_theme.dart
View file @
2e01eef5
...
...
@@ -7,11 +7,12 @@ import 'package:flutter/foundation.dart';
import
'basic.dart'
;
import
'framework.dart'
;
import
'icon_theme_data.dart'
;
import
'inherited_theme.dart'
;
/// Controls the default color, opacity, and size of icons in a widget subtree.
///
/// The icon theme is honored by [Icon] and [ImageIcon] widgets.
class
IconTheme
extends
Inherited
Widget
{
class
IconTheme
extends
Inherited
Theme
{
/// Creates an icon theme that controls the color, opacity, and size of
/// descendant widgets.
///
...
...
@@ -70,6 +71,12 @@ class IconTheme extends InheritedWidget {
@override
bool
updateShouldNotify
(
IconTheme
oldWidget
)
=>
data
!=
oldWidget
.
data
;
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
IconTheme
iconTheme
=
context
.
ancestorWidgetOfExactType
(
IconTheme
);
return
identical
(
this
,
iconTheme
)
?
child
:
IconTheme
(
data:
data
,
child:
child
);
}
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
...
...
packages/flutter/lib/src/widgets/inherited_theme.dart
0 → 100644
View file @
2e01eef5
// Copyright 2019 The Chromium Authors. All rights reserved.
// 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
'framework.dart'
;
/// An [InheritedWidget] that defines visual properties like colors
/// and text styles, which the [child]'s subtree depends on.
///
/// The [wrap] method is used by [captureAll] to construct a widget
/// that will wrap a child in all of the inherited themes which
/// are present in a build context but are not present in the
/// context that the returned widget is eventually built in.
///
/// A widget that's shown in a different context from the one it's
/// built in, like the contents of a new route or an overlay, will
/// be able to depend on inherited widget ancestors of the context
/// it's built in.
///
/// {@tool snippet --template=freeform}
/// This example demonstrates how `InheritedTheme.captureAll()` can be used
/// to wrap the contents of a new route with the inherited themes that
/// are present when the route is built - but are not present when route
/// is actually shown.
///
/// If the same code is run without `InheritedTheme.captureAll(), the
/// new route's Text widget will inherit the "something must be wrong"
/// fallback text style, rather than the default text style defined in MyApp.
///
/// ```dart imports
/// import 'package:flutter/material.dart';
/// ```
///
/// ```dart main
/// void main() {
/// runApp(MyApp());
/// }
/// ```
///
/// ```dart
/// class MyAppBody extends StatelessWidget {
/// @override
/// Widget build(BuildContext context) {
/// return GestureDetector(
/// onTap: () {
/// Navigator.of(context).push(
/// MaterialPageRoute(
/// builder: (BuildContext _) {
/// // InheritedTheme.captureAll() saves references to themes that
/// // are found above the context provided to this widget's build
/// // method, notably the DefaultTextStyle defined in MyApp. The
/// // context passed to the MaterialPageRoute's builder is not used,
/// // because its ancestors are above MyApp's home.
/// return InheritedTheme.captureAll(context, Container(
/// alignment: Alignment.center,
/// color: Theme.of(context).colorScheme.surface,
/// child: Text('Hello World'),
/// ));
/// },
/// ),
/// );
/// },
/// child: Center(child: Text('Tap Here')),
/// );
/// }
/// }
///
/// class MyApp extends StatelessWidget {
/// @override
/// Widget build(BuildContext context) {
/// return MaterialApp(
/// home: Scaffold(
/// // Override the DefaultTextStyle defined by the Scaffold.
/// // Descendant widgets will inherit this big blue text style.
/// body: DefaultTextStyle(
/// style: TextStyle(fontSize: 48, color: Colors.blue),
/// child: MyAppBody(),
/// ),
/// ),
/// );
/// }
/// }
/// ```
/// {@end-tool}
abstract
class
InheritedTheme
extends
InheritedWidget
{
/// Abstract const constructor. This constructor enables subclasses to provide
/// const constructors so that they can be used in const expressions.
const
InheritedTheme
({
Key
key
,
@required
Widget
child
,
})
:
super
(
key:
key
,
child:
child
);
/// Return a copy of this inherited theme with the specified [child].
///
/// If the identical inherited theme is already visible from [context] then
/// just return the [child].
///
/// This implementation for [TooltipTheme] is typical:
/// ```dart
/// Widget wrap(BuildContext context, Widget child) {
/// final TooltipTheme ancestorTheme = context.ancestorWidgetOfExactType(TooltipTheme);
/// return identical(this, ancestorTheme) ? child : TooltipTheme(data: data, child: child);
/// }
/// ```
Widget
wrap
(
BuildContext
context
,
Widget
child
);
/// Returns a widget that will [wrap] child in all of the inherited themes
/// which are visible from [context].
static
Widget
captureAll
(
BuildContext
context
,
Widget
child
)
{
assert
(
child
!=
null
);
assert
(
context
!=
null
);
final
List
<
InheritedTheme
>
themes
=
<
InheritedTheme
>[];
context
.
visitAncestorElements
((
Element
ancestor
)
{
if
(
ancestor
is
InheritedElement
&&
ancestor
.
widget
is
InheritedTheme
)
{
final
InheritedTheme
theme
=
ancestor
.
widget
;
themes
.
add
(
theme
);
}
return
true
;
});
return
_CaptureAll
(
themes:
themes
,
child:
child
);
}
}
class
_CaptureAll
extends
StatelessWidget
{
const
_CaptureAll
({
Key
key
,
@required
this
.
themes
,
@required
this
.
child
})
:
assert
(
themes
!=
null
),
assert
(
child
!=
null
),
super
(
key:
key
);
final
List
<
InheritedTheme
>
themes
;
final
Widget
child
;
@override
Widget
build
(
BuildContext
context
)
{
Widget
wrappedChild
=
child
;
for
(
InheritedTheme
theme
in
themes
)
wrappedChild
=
theme
.
wrap
(
context
,
wrappedChild
);
return
wrappedChild
;
}
}
packages/flutter/lib/src/widgets/text.dart
View file @
2e01eef5
...
...
@@ -7,6 +7,7 @@ import 'package:flutter/painting.dart';
import
'basic.dart'
;
import
'framework.dart'
;
import
'inherited_theme.dart'
;
import
'media_query.dart'
;
// Examples can assume:
...
...
@@ -20,7 +21,7 @@ import 'media_query.dart';
/// smoothly over a given duration.
/// * [DefaultTextStyleTransition], which takes a provided [Animation] to
/// animate changes in text style smoothly over time.
class
DefaultTextStyle
extends
Inherited
Widget
{
class
DefaultTextStyle
extends
Inherited
Theme
{
/// Creates a default text style for the given subtree.
///
/// Consider using [DefaultTextStyle.merge] to inherit styling information
...
...
@@ -161,6 +162,20 @@ class DefaultTextStyle extends InheritedWidget {
textWidthBasis
!=
oldWidget
.
textWidthBasis
;
}
@override
Widget
wrap
(
BuildContext
context
,
Widget
child
)
{
final
DefaultTextStyle
defaultTextStyle
=
context
.
ancestorWidgetOfExactType
(
DefaultTextStyle
);
return
identical
(
this
,
defaultTextStyle
)
?
child
:
DefaultTextStyle
(
style:
style
,
textAlign:
textAlign
,
softWrap:
softWrap
,
overflow:
overflow
,
maxLines:
maxLines
,
textWidthBasis:
textWidthBasis
,
child:
child
,
);
}
@override
void
debugFillProperties
(
DiagnosticPropertiesBuilder
properties
)
{
super
.
debugFillProperties
(
properties
);
...
...
packages/flutter/lib/widgets.dart
View file @
2e01eef5
...
...
@@ -52,6 +52,7 @@ export 'src/widgets/image_icon.dart';
export
'src/widgets/implicit_animations.dart'
;
export
'src/widgets/inherited_model.dart'
;
export
'src/widgets/inherited_notifier.dart'
;
export
'src/widgets/inherited_theme.dart'
;
export
'src/widgets/layout_builder.dart'
;
export
'src/widgets/list_wheel_scroll_view.dart'
;
export
'src/widgets/localizations.dart'
;
...
...
packages/flutter/test/material/inherited_theme_test.dart
0 → 100644
View file @
2e01eef5
This diff is collapsed.
Click to expand it.
packages/flutter/test/widgets/inherited_theme_test.dart
0 → 100644
View file @
2e01eef5
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/widgets.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
class
TestRoute
extends
PageRouteBuilder
<
void
>
{
TestRoute
(
Widget
child
)
:
super
(
pageBuilder:
(
BuildContext
_
,
Animation
<
double
>
__
,
Animation
<
double
>
___
)
=>
child
,
);
}
class
IconTextBox
extends
StatelessWidget
{
const
IconTextBox
(
this
.
text
);
final
String
text
;
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
alignment:
Alignment
.
center
,
child:
Row
(
children:
<
Widget
>[
const
Icon
(
IconData
(
0x41
,
fontFamily:
'Roboto'
)),
Text
(
text
)],
),
);
}
}
void
main
(
)
{
testWidgets
(
'InheritedTheme.captureAll()'
,
(
WidgetTester
tester
)
async
{
const
double
fontSize
=
32
;
const
double
iconSize
=
48
;
const
Color
textColor
=
Color
(
0xFF00FF00
);
const
Color
iconColor
=
Color
(
0xFF0000FF
);
bool
useCaptureAll
=
false
;
BuildContext
navigatorContext
;
Widget
buildFrame
()
{
return
WidgetsApp
(
color:
const
Color
(
0xFFFFFFFF
),
onGenerateRoute:
(
RouteSettings
settings
)
{
return
TestRoute
(
// The outer DefaultTextStyle and IconTheme widgets must have
// no effect on the test because InheritedTheme.captureAll()
// is required to only save the closest InheritedTheme ancestors.
DefaultTextStyle
(
style:
const
TextStyle
(
fontSize:
iconSize
,
color:
iconColor
),
child:
IconTheme
(
data:
const
IconThemeData
(
size:
fontSize
,
color:
textColor
),
// The inner DefaultTextStyle and IconTheme widgets define
// InheritedThemes that captureAll() will wrap() around
// TestRoute's IconTextBox child.
child:
DefaultTextStyle
(
style:
const
TextStyle
(
fontSize:
fontSize
,
color:
textColor
),
child:
IconTheme
(
data:
const
IconThemeData
(
size:
iconSize
,
color:
iconColor
),
child:
Builder
(
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
behavior:
HitTestBehavior
.
opaque
,
onTap:
()
{
navigatorContext
=
context
;
Navigator
.
of
(
context
).
push
(
TestRoute
(
useCaptureAll
?
InheritedTheme
.
captureAll
(
context
,
const
IconTextBox
(
'Hello'
))
:
const
IconTextBox
(
'Hello'
)
),
);
},
child:
const
IconTextBox
(
'Tap'
),
);
},
),
),
),
),
),
);
},
);
}
TextStyle
getIconStyle
()
{
return
tester
.
widget
<
RichText
>(
find
.
descendant
(
of:
find
.
byType
(
Icon
),
matching:
find
.
byType
(
RichText
),
),
).
text
.
style
;
}
TextStyle
getTextStyle
(
String
text
)
{
return
tester
.
widget
<
RichText
>(
find
.
descendant
(
of:
find
.
text
(
text
),
matching:
find
.
byType
(
RichText
),
),
).
text
.
style
;
}
useCaptureAll
=
false
;
await
tester
.
pumpWidget
(
buildFrame
());
expect
(
find
.
text
(
'Tap'
),
findsOneWidget
);
expect
(
find
.
text
(
'Hello'
),
findsNothing
);
expect
(
getTextStyle
(
'Tap'
).
color
,
textColor
);
expect
(
getTextStyle
(
'Tap'
).
fontSize
,
fontSize
);
expect
(
getIconStyle
().
color
,
iconColor
);
expect
(
getIconStyle
().
fontSize
,
iconSize
);
// Tap to show the TestRoute
await
tester
.
tap
(
find
.
text
(
'Tap'
));
await
tester
.
pumpAndSettle
();
// route transition
expect
(
find
.
text
(
'Tap'
),
findsNothing
);
expect
(
find
.
text
(
'Hello'
),
findsOneWidget
);
// The new route's text and icons will NOT inherit the DefaultTextStyle or
// IconTheme values.
expect
(
getTextStyle
(
'Hello'
).
color
,
isNot
(
textColor
));
expect
(
getTextStyle
(
'Hello'
).
fontSize
,
isNot
(
fontSize
));
expect
(
getIconStyle
().
color
,
isNot
(
iconColor
));
expect
(
getIconStyle
().
fontSize
,
isNot
(
iconSize
));
// Return to the home route
useCaptureAll
=
true
;
Navigator
.
of
(
navigatorContext
).
pop
();
await
tester
.
pumpAndSettle
();
// route transition
// Verify that all is the same as it was when the test started
expect
(
find
.
text
(
'Tap'
),
findsOneWidget
);
expect
(
find
.
text
(
'Hello'
),
findsNothing
);
expect
(
getTextStyle
(
'Tap'
).
color
,
textColor
);
expect
(
getTextStyle
(
'Tap'
).
fontSize
,
fontSize
);
expect
(
getIconStyle
().
color
,
iconColor
);
expect
(
getIconStyle
().
fontSize
,
iconSize
);
// Tap to show the TestRoute. The test route's IconTextBox will have been
// wrapped with InheritedTheme.captureAll().
await
tester
.
tap
(
find
.
text
(
'Tap'
));
await
tester
.
pumpAndSettle
();
// route transition
expect
(
find
.
text
(
'Tap'
),
findsNothing
);
expect
(
find
.
text
(
'Hello'
),
findsOneWidget
);
// The new route's text and icons will inherit the DefaultTextStyle or
// IconTheme values because captureAll.
expect
(
getTextStyle
(
'Hello'
).
color
,
textColor
);
expect
(
getTextStyle
(
'Hello'
).
fontSize
,
fontSize
);
expect
(
getIconStyle
().
color
,
iconColor
);
expect
(
getIconStyle
().
fontSize
,
iconSize
);
});
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment