Flutter 多引擎渲染,TextField 踩坑指南

915 阅读2分钟

承接上文:《Flutter 多引擎渲染,在稿定 App 的实践(三):躺坑篇》

先吐槽,这多引擎渲染的坑真的是多,但好在努努力也都能解决掉 ~

这次对 TextField 单独开一篇说明,也算是把上文未完善的

M. Flutter 开发需要注意的 Root 不是一个 MaterialApp 会产生的问题

一次性完善掉了。

起因

笔者在开发一个通用输入框组件,在测试用例中完全正常,如下图

image.png

但是通过 FlutterEngineGroup 多引擎渲染集成到 Native 项目时,报错如下:

1666076764481.jpg

解决方式

看报错信息得知, TextField 竟然需要一个 Material 父节点 [狗头] ...

也去翻一下 TextField 源码,看到如下的注释:

image.png

确实需要用 decoration 来绘制全边框的样式,那就乖乖听话,补上应该就行了吧。

Material(
  child: TextField(...)
)

如果各位同学没看前几篇文章,直接看这篇可能会问为什么不用 MaterialApp or Scaffold。那建议还是翻一下前几篇文章,还不是一两句能说清的。

但报错就变成:

1666076785854.jpg

WTF,还要 MaterialLocalizations ???

我也是无力吐槽了,网上翻了翻,大部分都是说用 MaterialApp,可是多引擎渲染下又用不了它,真的怪不得用的人那么少。

好在,翻到官方文档(最后的救命稻草)TextField requires a MaterialLocalizations widget

可以看到这是一篇迁移文档,在 Flutter 1.20 年代,TextField 增加了必要 Material

迁移文档写的很详细,所以直接可以用它迁移后的写法,也算是一个全家桶,如果不用 MaterialApp,那应该去使用的父节点一并介绍了出来,有些多,所以就简单封装了下来使用

class MaterialWidget extends StatelessWidget {
  final Widget child;

  const MaterialWidget({Key? key, required this.child}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Localizations(
      locale: const Locale('en', 'US'),
      delegates: const <LocalizationsDelegate<dynamic>>[
        DefaultWidgetsLocalizations.delegate,
        DefaultMaterialLocalizations.delegate,
      ],
      child: MediaQuery(
        data: const MediaQueryData(),
        child: Directionality(
          textDirection: TextDirection.ltr,
          child: Material(
            color: Colors.transparent,
            child: child,
          ),
        ),
      ),
    );
  }
}

然后,把“自动生成”的模版代码中的 Directionality 替换为 MaterialWidget,来避免团队内其他人踩坑。

其他注意事项

TextField 在多引擎渲染下使用还有些其他问题:

不能使用推荐的键盘弹出监听

Flutter 官方推荐使用的

/// 方式1
Scaffold(
  resizeToAvoidBottomInset: true,
  child: ...
)

/// 方式2
Container(
  padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
  child: ...,
);

这两种方式都是不能用的,笔者的解决方式是在 Native 封装监听,由 Native 来控制 View 位置上移。

注意 Material 自带背景色

所以笔者在封装的基类中增加了 color: Colors.transparent

==== 2022.10.19 持续掉坑分割线 ====

注意需要父节点还需要是一个 Overlay

image.png

Debug 下会 assert 到这个位置,页面显示是正常的,但键盘输入结果你收不到 !!!

TextFieldonChange 事件没反应 !!!

直接放改后的代码:

  @override
  Widget build(BuildContext context) {
    return MaterialWidget(
      child: Overlay(
        initialEntries: [
          OverlayEntry(
            builder: (context) {
              return ...
            },
          ),
        ],
      ),
    );
  }