flutter 展示的字体突然奔放了

0 阅读2分钟

开始的时候好好的

突然就奔放起来了

没想到,没想到啊

一、现象

界面突然风格变了。

异常

字体变大了,而且没有指定颜色的,用了大红色。 Text都有黄色的双下划线。

这个代码没有改动的。正常情况应该是:

right_pitch

这是想要的效果。

二、结论

flutter_easyloading: ^4.0.2

升级后导致问题。上一个版本3.0.5是2022.05.23 发布的,终于发布4.X版本,更新日志没有说会影响到啥。没想到对于showCupertinoModalPopup()竟然会有样式的影响。

解决方法

EasyLoading初始化的时候,修改为:

builder: EasyLoading.init(
  builder: (context, child) {
    return DefaultTextStyle(style: Theme.of(context).textTheme.bodyMedium!, child: child!);
  },
)

找了很久没有找到原因,还是AI帮我找到的。以后我应该是测试人员,而不是开发人员了。

三、原因

EasyLoading的初始化是一样的。

MaterialApp(
    initialRoute: "/",
    builder: EasyLoading.init(),
)

1. 旧版本

EasyLoading在3.0.5版本中:

@override
  Widget build(BuildContext context) {
    return Material(
      child: Overlay(
        initialEntries: [
          EasyLoadingOverlayEntry(
            builder: (BuildContext context) {
              if (widget.child != null) {
                return widget.child!;
              } else {
                return Container();
              }
            },
          ),
          _overlayEntry,
        ],
      ),
    );
  }

这个 Material 会给下面的根 Navigator/Overlay 提供正常的 Material 默认文字样式。

所以在使用 showCupertinoModalPopup的时候用到了EasyLoading设置的Material

2. 新版本

EasyLoading在4.X版本中:

@override
  Widget build(BuildContext context) {
    _syncOverlay();
    final session = easyLoadingRuntime.session;
    return Stack(
      fit: StackFit.passthrough,
      clipBehavior: Clip.none,
      children: <Widget>[
        Material(
          type: MaterialType.transparency,
          textStyle: DefaultTextStyle.of(context).style,
          child: widget.child ?? const SizedBox.shrink(),
        ),
        if (session != null)
          Positioned.fill(
            child: _EasyLoadingOverlay(
              key: _overlayKey,
              session: session,
              onPresented: () => easyLoadingRuntime.didPresent(session.id),
              onDismiss: () {
                unawaited(
                  easyLoadingRuntime.dismiss(
                    reason: EasyLoadingDismissReason.tap,
                  ),
                );
              },
            ),
          ),
      ],
    );
  }
}

设置的textStyleDefaultTextStyle.of(context).style, 也就是MaterialApp中的样式。

SO showCupertinoModalPopup使用到了EasyLoading设置的Material

3. 原因

执行了showCupertinoModalPopup后的图层结构为:

MaterialApp
└─ EasyLoading 包装层
   └─ 根 Navigator
      └─ Overlay
         ├─ 原页面 Route
         │  └─ Scaffold
         │     └─ 正常 Material 文字环境
         │
         └─ CupertinoModalPopupRoute
            └─ CouponPackageDetail

CouponPackageDetail 为弹窗中的视图,它没有设置Material。SO 继承了根Navigator上面的EasyLoading包装层的Material

旧版本

没有指定textStyle,所以使用了默认的Theme.of(context).textTheme.bodyMedium.

新版本

指定textStyleDefaultTextStyle.of(context).style,此DefaultTextStyle获取到的是MaterialApp中的textStyle:

Widget _buildWidgetApp(BuildContext context) {
    final Color materialColor = widget.color ?? widget.theme?.primaryColor ?? Colors.blue;
    if (_usesRouter) {
      return WidgetsApp.router(
        key: GlobalObjectKey(this),
        routeInformationProvider: widget.routeInformationProvider,
        routeInformationParser: widget.routeInformationParser,
        routerDelegate: widget.routerDelegate,
        routerConfig: widget.routerConfig,
        backButtonDispatcher: widget.backButtonDispatcher,
        onNavigationNotification: widget.onNavigationNotification,
        builder: _materialBuilder,
        title: widget.title,
        onGenerateTitle: widget.onGenerateTitle,
        textStyle: _errorTextStyle,
        color: materialColor,
        locale: widget.locale,
        localizationsDelegates: _localizationsDelegates,
        localeResolutionCallback: widget.localeResolutionCallback,
        localeListResolutionCallback: widget.localeListResolutionCallback,
        supportedLocales: widget.supportedLocales,
        showPerformanceOverlay: widget.showPerformanceOverlay,
        showSemanticsDebugger: widget.showSemanticsDebugger,
        debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner,
        exitWidgetSelectionButtonBuilder: _exitWidgetSelectionButtonBuilder,
        moveExitWidgetSelectionButtonBuilder: _moveExitWidgetSelectionButtonBuilder,
        tapBehaviorButtonBuilder: _tapBehaviorButtonBuilder,
        shortcuts: widget.shortcuts,
        actions: widget.actions,
        restorationScopeId: widget.restorationScopeId,
      );
    }

_MaterialAppStatebuild设置为_errorTextStyle:

const TextStyle _errorTextStyle = TextStyle(
  color: Color(0xD0FF0000),
  fontFamily: 'monospace',
  fontSize: 48.0,
  fontWeight: FontWeight.w900,
  decoration: TextDecoration.underline,
  decorationColor: Color(0xFFFFFF00),
  decorationStyle: TextDecorationStyle.double,
  debugLabel: 'fallback style; consider putting your text in a Material',
);

对,就是它,看到的就是它。

如果弹窗等``

四、 Overlay

Overlay 是 Flutter 中专门用来“叠加显示 UI”的一个容器。它允许新的 Widget 覆盖在当前页面上面,而不需要替换当前页面。

Navigator中的Overlay有很多Route:

Navigator
└─ Overlay
   ├─ Route A
   ├─ Route B
   ├─ Dialog Route
   ├─ Popup Route
   └─ 其他浮层

在执行showCupertinoModalPopup的时候:

MaterialApp
│
└─ EasyLoading
   │
   └─ Navigator
      │
      └─ Overlay
         │
         ├─ 原页面 Route
         │  └─ Scaffold
         │     └─ 页面内容
         │
         ├─ ModalBarrier
         │  └─ 半透明遮罩
         │
         └─ CupertinoModalPopupRoute
            └─ CouponPackageDetail

CouponPackageDetail不是弹窗所在的页面的child,而是创建了一个route: CupertinoModalPopupRoute, 所以不会继承原页面的Material

完结

AI时代,没有AI解决不了的问题。如果不能,请升级套餐。 _