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
class DefaultTextStyle extends InheritedTheme { static DefaultTextStyle of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<DefaultTextStyle>() ?? const DefaultTextStyle.fallback(); } }InheritedTheme 就是一个 InheritedWidget:
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
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( textStyle: TextStyle(fontSize: 31, color: Colors.red), child: Text('materical 中的style'), ),这样在Text的构建时,就可以通过 DefaultTextStyle.of(context);拿到父节点中的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, ), ); } }总结:
在Flutter中,Text小部件是会从其上层的DefaultTextStyle中继承样式的,而Material小部件本身就包含一个DefaultTextStyle。这就是为什么Text能够获取到Material的样式信息的原因。具体来说,DefaultTextStyle是一个InheritedWidget,它在widget树中传递默认文本样式。当Text小部件没有显式指定样式时,它会查找其父级上的DefaultTextStyle,并应用那里设置的默认样式。
在文章开头的例子中,Material小部件设置了textStyle,它实际上是在DefaultTextStyle中设置的默认样式。因此,Text小部件能够通过继承来获取Material的默认文本样式。这是Flutter中一种方便的方式,允许您在widget树中的某个位置设置默认样式,而不必手动为每个Text小部件设置样式。
从这个DefaultTextStyle 我们又重新看到了 InheritedWidget 的作用。