Text为什么可以从父节点Material获取textStyle

为什么 下面代码Text 能够从 Material获取textStyle

less 复制代码
Material(
  textStyle: TextStyle(fontSize: 31, color: Colors.red),
  child: Text('materical 中的style'),
),

1、 先看下Text 获取 textStyle:

scala 复制代码
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

scala 复制代码
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实现如下:

scala 复制代码
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

scala 复制代码
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

scala 复制代码
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,下面原理也是相同的:

less 复制代码
    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源码部分实现为:

scala 复制代码
  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 的作用。

相关推荐
恋猫de小郭28 分钟前
Android CLI ,谷歌为 Android 开发者专研的 AI Agent,提速三倍
android·前端·flutter
火柴就是我1 小时前
flutter pushAndRemoveUntil 的一次小疑惑
flutter
于慨2 小时前
flutter doctor问题解决
flutter
唔662 小时前
flutter 图片加载类 图片的安全使用
安全·flutter
Nathan202406163 小时前
Flutter - InheritedWidget
flutter·dart
恋猫de小郭3 小时前
JetBrains Amper 0.10 ,期待它未来替代 Gradle
android·前端·flutter
Lanren的编程日记4 小时前
Flutter鸿蒙应用开发:实时聊天功能集成实战
flutter·华为·harmonyos
Utopia^14 小时前
鸿蒙flutter第三方库适配 - 联系人备份工具
flutter·华为·harmonyos
念格20 小时前
Flutter 仿微信输入框最佳实践:自适应高度 + 超行数智能切换全屏
前端·flutter
程序员老刘21 小时前
《Flutter跨平台开发核心技巧与应用》新书来了
flutter·ai编程·客户端