如何创建类似Class.of(context)形式的Flutter自定义类
实现方案
你要的CustomTextStyles.of(context)调用形式和Flutter内置Theme.of、Scaffold.of的逻辑完全一致,不需要复杂依赖,按下面的写法实现即可:
最简实现(无额外依赖,开箱即用)
直接定义带私有构造、静态of方法的样式类,在of方法内接收context做动态样式计算,写完就能直接调用:
import 'package:flutter/material.dart'; class CustomTextStyles { final TextStyle h1; final TextStyle h2; final TextStyle bodyRegular; final TextStyle caption; // 私有构造,禁止外部手动实例化 const CustomTextStyles._({ required this.h1, required this.h2, required this.bodyRegular, required this.caption, }); // 核心of方法,接收BuildContext参数 static CustomTextStyles of(BuildContext context) { // 可以直接通过context取主题、屏幕尺寸等全局参数,做响应式适配 final currentTheme = Theme.of(context); final deviceWidth = MediaQuery.sizeOf(context).width; return CustomTextStyles._( h1: TextStyle( fontSize: deviceWidth > 600 ? 32 : 28, fontWeight: FontWeight.w700, color: currentTheme.colorScheme.onSurface, ), h2: TextStyle( fontSize: deviceWidth > 600 ? 24 : 22, fontWeight: FontWeight.w600, color: currentTheme.colorScheme.onSurface, ), bodyRegular: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, color: currentTheme.colorScheme.onSurfaceVariant, ), caption: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: currentTheme.colorScheme.outline, ), ); } }
直接在build方法里调用就行:
Text( "页面大标题", style: CustomTextStyles.of(context).h1, )
性能优化版本(全局缓存实例)
如果担心每次调用of都重复创建样式实例,可以搭配InheritedWidget做全局挂载缓存,和Flutter官方Theme的实现逻辑完全对齐:
- 第一步:定义私有InheritedWidget作为样式的挂载载体
class _CustomTextStylesScope extends InheritedWidget { final CustomTextStyles styles; const _CustomTextStylesScope({ required this.styles, required super.child, }); @override bool updateShouldNotify(covariant _CustomTextStylesScope oldWidget) { return styles != oldWidget.styles; } }
- 第二步:改造样式类,抽离实例创建逻辑,让of方法优先读取缓存
class CustomTextStyles { final TextStyle h1; final TextStyle h2; final TextStyle bodyRegular; final TextStyle caption; const CustomTextStyles._({ required this.h1, required this.h2, required this.bodyRegular, required this.caption, }); static CustomTextStyles of(BuildContext context) { final scope = context.dependOnInheritedWidgetOfExactType<_CustomTextStylesScope>(); // 有全局缓存就用缓存,没有就现场创建兜底 return scope?.styles ?? _createFromContext(context); } // 抽离样式创建逻辑 static CustomTextStyles _createFromContext(BuildContext context) { final currentTheme = Theme.of(context); final deviceWidth = MediaQuery.sizeOf(context).width; return CustomTextStyles._( h1: TextStyle( fontSize: deviceWidth > 600 ? 32 : 28, fontWeight: FontWeight.w700, color: currentTheme.colorScheme.onSurface, ), h2: TextStyle( fontSize: deviceWidth > 600 ? 24 : 22, fontWeight: FontWeight.w600, color: currentTheme.colorScheme.onSurface, ), bodyRegular: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, color: currentTheme.colorScheme.onSurfaceVariant, ), caption: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: currentTheme.colorScheme.outline, ), ); } }
- 第三步:在App根节点挂载全局样式,注意要用Builder拿MaterialApp内部的context,否则会拿不到Theme、MediaQuery的实例:
class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Builder( builder: (innerContext) { return _CustomTextStylesScope( styles: CustomTextStyles._createFromContext(innerContext), child: const HomePage(), ); }, ), ); } }
注意:如果不需要响应全局主题、屏幕尺寸变化,也可以直接在类里写固定的静态TextStyle常量,不需要传context,但这种写法无法适配多主题、横竖屏切换的场景。
内容的提问来源于stack exchange,提问作者Gabrielius Pileckis
相关产品推荐
相关产品推荐

