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 的作用。

相关推荐
ALLIN18 小时前
Flutter 三种方式实现页面切换后保持原页面状态
flutter
Dabei18 小时前
Flutter 国际化
flutter
Dabei18 小时前
Flutter MQTT 通信文档
flutter
Dabei21 小时前
Flutter 中实现 TCP 通信
flutter
孤鸿玉21 小时前
ios flutter_echarts 不在当前屏幕 白屏修复
flutter
前端 贾公子1 天前
《Vuejs设计与实现》第 16 章(解析器) 上
vue.js·flutter·ios
tangweiguo030519871 天前
Flutter 数据存储的四种核心方式 · 从 SharedPreferences 到 SQLite:Flutter 数据持久化终极整理
flutter
0wioiw01 天前
Flutter基础(②④事件回调与交互处理)
flutter
肥肥呀呀呀1 天前
flutter配置Android gradle kts 8.0 的打包名称
android·flutter
吴Wu涛涛涛涛涛Tao2 天前
Flutter 实现「可拖拽评论面板 + 回复输入框 + @高亮」的完整方案
android·flutter·ios