为什么 下面代码Text 可以从 Material获取textStyle
Material(
textStyle: TextStyle(fontSize: 31, color: Colors.red),
child: Text('materical 中的style'),
),
1、 先看下Text 获取 textStyle:
class Text extends StatelessWidget {
Widget build(BuildContext context) {
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context); //
TextStyle? effectiveTextStyle = style;
if (style == null || style!.inherit) {
effectiveTextStyle = defaultTextStyle.style.merge(style);
}
}
}
这儿运用 DefaultTextStyle
DefaultTextStyle.of(context);完成:
DefaultTextStyle 是一个 InheritedWidget
class DefaultTextStyle extends InheritedTheme {
static DefaultTextStyle of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<DefaultTextStyle>() ?? const DefaultTextStyle.fallback();
}
}
InheritedTheme 便是一个 InheritedWidget:
abstract class InheritedTheme extends InheritedWidget
context.dependOnInheritedWidgetOfExactType()
方法的完成为 Element中,由于 context便是一个 Element,dependOnInheritedWidgetOfExactType完成如下:
abstract class Element extends DiagnosticableTree implements BuildContext {
@override
T? dependOnInheritedWidgetOfExactType<T extends InheritedWidget>({Object? aspect}) {
assert(_debugCheckStateIsActiveForAncestorLookup());
final InheritedElement? ancestor = _inheritedWidgets == null ? null : _inheritedWidgets![T];
if (ancestor != null) {
return dependOnInheritedElement(ancestor, aspect: aspect) as T;
}
_hadUnsatisfiedDependencies = true;
return null;
}
}
2、在看下Material
Material
class Material extends StatefulWidget {
State<Material> createState() => _MaterialState();
}
class _MaterialState extends State<Material> with TickerProviderStateMixin {
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context);
///...
Widget? contents = widget.child;
if (contents != null) {
//
contents = AnimatedDefaultTextStyle(
style: widget.textStyle ?? Theme.of(context).textTheme.bodyText2!,
duration: widget.animationDuration,
child: contents,
);
}
//....
if (widget.type == MaterialType.canvas && widget.shape == null && widget.borderRadius == null) {
return AnimatedPhysicalModel(
//...
child: contents,
);
}
final ShapeBorder shape = _getShape();
if (widget.type == MaterialType.transparency) {
return _transparentInterior(
////..
contents: contents,
);
}
return _MaterialInterior(
//...
child: contents,
);
}
}
AnimatedDefaultTextStyle
class AnimatedDefaultTextStyle extends ImplicitlyAnimatedWidget {
AnimatedWidgetBaseState<AnimatedDefaultTextStyle> createState() => _AnimatedDefaultTextStyleState();
}
abstract class ImplicitlyAnimatedWidget extends StatefulWidget
class _AnimatedDefaultTextStyleState extends AnimatedWidgetBaseState<AnimatedDefaultTextStyle> {
@override
Widget build(BuildContext context) {
return DefaultTextStyle(
style: _style!.evaluate(animation),
child: widget.child,
);
}
}
DefaultTextStyle
Material 是由 一个DefaultTextStyle 包裹了child子widget的 小组件。
Material(
textStyle: TextStyle(fontSize: 31, color: Colors.red),
child: Text(‘materical 中的style’),
),
这样在Text的构建时,就可以经过 DefaultTextStyle.of(context);拿到父节点中的style数据了
3、扩展TextButton的child获取textStyle
可以扩展一下,Text也是可以获取TextButton的 style,下面原理也是相同的:
TextButton(
onPressed: () {},
style: TextButton.styleFrom(
textStyle: TextStyle(color: Colors.red, fontSize: 30)),
child:
Text('TextButton---text style'), //为什么可以获取到style中的text style
)
TextButton(
onPressed: () {},
style: TextButton.styleFrom(
textStyle: TextStyle(color: Colors.red, fontSize: 30)),
child: Column(
children: [
Text('123text style--随意套多少个子widget,都可以从父节点获取到style'),
Text('123---一切子Text都能获取父节点相同style值,并且不论套了多少层') //没有显现指定时,假如默许运用父级特点
],
)),
TextButton源码部分完成为:
class TextButton extends ButtonStyleButton
abstract class ButtonStyleButton extends StatefulWidget {
State<ButtonStyleButton> createState() => _ButtonStyleState();
}
class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStateMixin {
final Widget result = ConstrainedBox(
constraints: effectiveConstraints,
child: Material(
//..
textStyle: resolvedTextStyle?.copyWith(color: resolvedForegroundColor),
//...
);
return Semantics(
//...
child: _InputPadding(
//....
child: result,
),
);
}
}
4、inherit特点效果
回到刚开始的style和父级style获取上,
class Text extends StatelessWidget {
Widget build(BuildContext context) {
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context); //
TextStyle? effectiveTextStyle = style;
if (style == null || style!.inherit) {
effectiveTextStyle = defaultTextStyle.style.merge(style);
}
}
}
effectiveTextStyle = defaultTextStyle.style.merge(style);
widget树中传递默许文本款式。当Text
小部件没有显式指定款式时,它会查找其父级上的DefaultTextStyle
,并使用那里设置的默许款式。
TextStyle merge(TextStyle? other) {
if (other == null) {
return this;
}
if (!other.inherit) {//是否运用上层widget款式(当本次没有显现指定时)
return other;
}
return copyWith(
color: other.color,
backgroundColor: other.backgroundColor,
//...
);
}
///copyWith
TextStyle copyWith({
bool? inherit,
Color? color,
Color? backgroundColor,
double? fontSize,
//...
}) {
//...
return TextStyle(//
inherit: inherit ?? this.inherit,
fontSize: fontSize ?? this.fontSize,
//...
);
}
总结:
在Flutter中,Text
小部件是会从其上层的DefaultTextStyle
中继承款式的,而Material
小部件本身就包括一个DefaultTextStyle
。这便是为什么Text
可以获取到Material
的款式信息的原因。
具体来说,DefaultTextStyle
是一个InheritedWidget
,它在widget树中传递默许文本款式。当Text
小部件没有显式指定款式时,它会查找其父级上的DefaultTextStyle
,并使用那里设置的默许款式。
在文章最初的比如中,Material
小部件设置了textStyle
,它实际上是在DefaultTextStyle
中设置的默许款式。因此,Text
小部件可以经过继承来获取Material
的默许文本款式。
这是Flutter中一种便利的方法,答应您在widget树中的某个位置设置默许款式,而不用手动为每个Text
小部件设置款式。
从这个DefaultTextStyle 咱们又重新看到了 InheritedWidget 的效果。