0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

详解TextField的主要构成部分

谷歌开发者 来源:CNDS技术社区 作者:恋猫de小郭 2022-03-18 12:29 次阅读
看完本篇,您不仅会了解到 TextField 的实现和构成,还可以学到很多之前不常用的"奇怪"知识。

在 Flutter 里TextField是一个比较复杂的控件,而在整个TextField里嵌套了许多不同实现的控件,它们组成了我们常用的输入框效果,如下图所示是关于TextField的主要构成部分,也是本篇主要讲解的内容。

87ae0bd4-8fb7-11ec-952b-dac502259ad0.png

FocusTrapArea

FocusTrapArea大家可能会比较陌生,这个是最近的版本里才出现的控件,FocusTrapArea本身并没有特别,它仅仅是在RenderObject tree里塞进去了一个FocusNode 它的出现主要是为了 Web/Desktop 平台,通过增加了FocusTrapArea之后,在 Web/Desktop 平台执行TextEditingController.clear的时候,TextField 还能继续保持之前获得的焦点。

具体可见Flutter的issues:#86154、#86041

MouseRegion

顾名思义是用于处理鼠标相关事件,主要用于响应鼠标独占的 Pointer 事件,比如:鼠标进入/离开控件区域、光标显示效果等等。

IgnorePointer

它在TextField里主要用于处理当前输入框是否可用的的状态,比如当widget.enabled或者widget.decoration?.enabledfalse时,IgnorePointer就会屏蔽整个区域内的手势事件,从而让TextField会无法点击输入。

TextSelectionGestureDetectorBuilder

关于TextSelectionGestureDetectorBuilder大家应该比较少接触,而在TextField里使用的是它的子类_TextFieldSelectionGestureDetectorBuilder:

它主要是处理TextField内针对EditableText的点击、滑动、长按等事件,例如单击弹起键盘,长按弹出选择复制/粘贴框等等。

TextSelectionGestureDetectorBuilder 的内部主要是通过 editableTextKey 这个 GlobalKey 去获取到 EditableTextState,从而将各种手势事件和 EditableText 里的行为关联起来。

该控件内部使用的是TextSelectionGestureDetector

例如在 _TextFieldSelectionGestureDetectorBuilder 中,可以看到 onSingleTapUp 的处理流程:

87e0efc2-8fb7-11ec-952b-dac502259ad0.png

如上代码所示:

1、收起已经弹出的 Toolbar (一个 Overlay,也就是复制/粘贴之类的弹框);2、根据不同平台选择响应事件;3、执行弹出键盘操作;4、回调点击事件
所以可以看到,这里其实是先执行弹出键盘,然后再回调点击的 callback,所以如果您需要在点击弹出键盘前,针对 TextField 作一些处理,那么 TextFieldonTap 其实并不合适,因为它是已经弹出了。 最后 _TextFieldSelectionGestureDetectorBuilder 会调用 buildGestureDetector 方法生成一个监听和处理触摸的控件,用于嵌套 child。

‍‍‍‍‍‍‍‍‍‍‍InputDecorator‍‍‍‍‍‍‍‍‍‍‍

关于 InputDecorator 的内部参数解析这里就不多说,以前在书里已经有详细介绍过,用过 TextField 的大家对于 InputDecorator 应该也不会陌生,TextFieldInputDecorator 的实现是和 AnimatedBuilder 一起组成使用。

因为在 TextFieldFocusNodeTextEditingController 都是 ChangeNotifier (Listenable),所以它们可以被用于 AnimatedBuilderanimation

87f0d0a4-8fb7-11ec-952b-dac502259ad0.png

也就是当 FocusNodeTextEditingController 这两者发生改变的时候,会让 InputDecorator 重新 rebuild 从而改变渲染效果,例如: 输入框输入内容时、焦点发生改变时修改输入框的背景颜色。

注意别搞混了InputDecoratorInputDecorationInputDecoration 是用来配置InputDecorator

所以可以看到InputDecorator有很丰富的参数和配置,开发者可以通过InputDecoration来配置很丰富的输入框 UI 效果,但是如果刚好出现某些位置,或者某些缝隙不满足产品诡异的需求时,那恭喜您,您开启了 Flutter 高级开发的修炼之路

为什么呢? 简单来说 InputDecorator 的实现是在内部是一个自定义的 RenderBox,其中和 layout 相关部分就有 600 多行的代码,也就是根据 InputDecorationiconprefixIconsuffix 等参数,进行定位布局,计算位置方向,根据基线调整位置等等。

另外 InputDecorator里的动画效果主要是通过内部的AnimatedOpacity等完成。

所以对于 InputDecorator 来说,如果您对于某些位置或者边界效果不满意,要么您就重构一个自己的实现,要么可能就要选择 "委曲求全"。

RepaintBoundary

为什么 TextField 内部会有一个 RepaintBoundary?首先 RepaintBoundary 是干嘛的?

之前在《Flutter 画面渲染的全面解析》详细介绍过这部分的知识,这简单不严谨地说就是:RepaintBoundary 主要是用于形成一个 Layer,得到一个独立的绘制区域。

常见的就是 Navigator 的页面跳转,内部基础实现都有一个 RepaintBoundary 来保证每个区域都是独立的绘制区域。

另外说到Navigator 就不得不说每个页面也都有自己的FocusScope,也就是我们常用的FocusScope.of(context)等用于键盘和焦点处理。
TextField 内部有一个 RepaintBoundary,是因为 TextField 本身是一个需要频繁更新的控件,而 TextField 里的内容变化一般很少需要触发父布局的重绘,所以 RepaintBoundary 的存在让 TextField 可以实现性能更好的局部绘制。

UnmanagedRestorationScope

UnmanagedRestorationScope 大家可能比较少用到,它本身是一个 InheritedWidget,主要是往下共享一个 RestorationBucketRestorationBucket 主要是和实现状态的保存/恢复有关系。

例如应用因为低内存在后台被回收时,可以通过它在重新回到 App 时恢复指定的数据,举个例子:

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    return MaterialApp(      // Give your RootRestorationScope an id, defaults to null.      restorationScopeId: 'root',       home: HomePage(),    );  }}
class HomePage extends StatefulWidget {  @override  _HomePageState createState() => _HomePageState();}
// Our state should be mixed-in with RestorationMixinclass _HomePageState extends State<HomePage> with RestorationMixin {
  // For each state, we need to use a restorable property  final RestorableInt _index = RestorableInt(0);
  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(child: Text('Index is ${_index.value}')),      bottomNavigationBar: BottomNavigationBar(        currentIndex: _index.value,        onTap: (i) => setState(() => _index.value = i),        items: [          BottomNavigationBarItem(              icon: Icon(Icons.home),              label: 'Home'          ),          BottomNavigationBarItem(              icon: Icon(Icons.notifications),              label: 'Notifications'          ),          BottomNavigationBarItem(              icon: Icon(Icons.settings),              label: 'Settings'          ),        ],      ),    );  }
  @override  // The restoration bucket id for this page,  // let's give it the name of our page!  String get restorationId => 'home_page';
  @override  void restoreState(RestorationBucket? oldBucket, bool initialRestore) {    // Register our property to be saved every time it changes,    // and to be restored every time our app is killed by the OS!    registerForRestoration(_index, 'nav_bar_index');  }}

如上代码所示:

  • 首先给 MaterialApp 配置 restorationScopeId (必须配置才算开启该功能)。

  • 使用 RestorableInt 用于配置和保存 BottomNavigationBarindex

  • State 混入 RestorationMixin 并且在 restoreState 方法里恢复 index 的状态;

其中默认 MaterialApp 内部用到了 RootRestorationScope,而 RootRestorationScope的内部就是 UnmanagedRestorationScope;上述例子运行后通过打开模拟器开发者设置里的 Don't keep activities 就可以看到效果。

以上示例来自《Introduction to State Restoration in Flutter》。

回到 TextField,在 _TextFieldState 里就混入了 RestorationMixin,然后使用 RestorableTextEditingController 用于用于恢复 TextEditingController

因为输入框的内容默认保存在了TextEditingControllerTextEditingValue里,所以这里用的是RestorableTextEditingController

88186dd0-8fb7-11ec-952b-dac502259ad0.png

一般情况下是使用 MaterialApp 内部默认自带了一个 RootRestorationScope,所以我们只需要给 MaterialApp 设置 restorationScopeIdTextFild 通过内置 UnmanagedRestorationScope 相关的逻辑,最终实现了文本内容的保存与恢复。

EditableText

EditableText 就不用多说了,TextField 的本体,内部主要通过 Scrollable 来实现滑动,同样的它也用了对应的 restorationId 来实现恢复和缓存。

首先注意到可以滑动这一点,可以看到对于 EditableText 来说,它其实是一个 "ViewPort",是根据 ViewportOffset 来实现滑动效果。

而对于 EditableText 内部,它使用了 CompositedTransformTarget 来实现 Toolbar 和输入框的联动,也就是输入控件和长按 "粘贴/复制" 弹出框之间的关联。

所以这里简单介绍下 CompositedTransformTarget,它通常和 CompositedTransformFollower 一起被用于控件之间的联动效果。

如上图所示,常见内置的 Slider,在滑动的弹出部分实现,就是通过 CompositedTransformTargetCompositedTransformFollower 的结合实现,它可以让一个控件跟随另外一个控件而无需计算位置,它们之间主要是通过 LayerLink 链接在一起。 回到 TextField,其实除了 "复制/粘贴"的 Toolbar,关于 selection 选中区域的内容,EditableText 内部也是通过类似的方式实现,只是这里是直接通过 LeaderLayer 而不是通过它的封装 CompositedTransformTarget 去实现。

当然使用 CompositedTransformTarget 还是会有 "比较大" 的性能开销,不建议大规模频繁使用,因为毕竟它属于一个 pushLayer 的操作。

另外 EditableText 内部绘制内容的部分,主要就是大家都知道的 TextPainter,这部分就没什么特别,暂时不详细展开。

所以本篇主要是通过介绍 TextField 的组成,以及解释内部各组成部分的作用,让开发者可以更清晰的了解 Flutter 里常用的文本输入框的实现,当遇上问题或者需求时,可以快速定位和解决问题,例如:

  • "粘贴/复制"的 Toolbar 是哪里弹出;

  • Toolbar 是如何定位和布局;
  • 点击 TextField 是如何弹出键盘和处理手势事件;
  • TextField 如何做到局部绘制;
  • ...

最后介绍一个简单的问题,之前有人刚好问我: 如何在 Flutter 上实现类似微信聊天输入框从一行到多行的输入框效果,如下图代码所示,就是这么简单:

TextField(  focusNode: _focusNode,  maxLines: 7,  minLines: 1,  decoration:      const InputDecoration(border: OutlineInputBorder()),)

原文标题:Flutter 快速解析 TextField 的内部原理 | 开发者说·DTalk

文章出处:【微信公众号:谷歌开发者】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 显示
    +关注

    关注

    0

    文章

    408

    浏览量

    44924
  • 参数
    +关注

    关注

    11

    文章

    1398

    浏览量

    31470
  • 模拟器
    +关注

    关注

    2

    文章

    817

    浏览量

    42697

原文标题:Flutter 快速解析 TextField 的内部原理 | 开发者说·DTalk

文章出处:【微信号:Google_Developers,微信公众号:谷歌开发者】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    ESD门禁系统主要构成部分有哪些

     ESD门禁系统由静电综合测试模块、机芯、闸机、识别模块、闸机控制模块、管理软件等构成。  1、静电综合测试模块。根据国家相关标准对穿着防静电鞋的脚部和戴着防静电腕带的手部分别同时进行静电检测,只有
    发表于 11-18 09:59

    挤出中空成型机的主要构成部分

    `挤出中空成型机主要构成部分,分为四部分,分别是机械、电气、液压、气路、水路。岩康小编将分别根据挤出中空成型机的几个主要
    发表于 07-13 16:20

    ISP的主要内部构成

    目录ISP的主要内部构成:ISP内部包含 CPU、SUP IP(各种功能模块的通称)、IF 等设备ISP的控制结构:1、ISP逻辑 2、运行在其上的firmwareISP上的Firmware包含三部分:AP对ISP的操控方式:外
    发表于 07-26 06:42

    Etest_CPS系统主要由哪些部分构成

    设备组成Etest_CPS系统主要由硬件部分与软件部分组成。硬件部分由PCI机箱、PCI控制器以及各种PCI接口板卡组成。软件部分由测试设计
    发表于 09-08 07:05

    构成微机系统CPU的两部分是什么

    2008年(下)高等教育自学考试全国统一命题考试工业用微型计算机试卷及答案详解(考试时间150分钟)第一部分选择题一、单项选择题(本大题共20小题,每小题2分,共40分)在每小题列出的四个备选项中
    发表于 09-10 07:54

    HarmonyOS实战——TextField文本输入框组件基本使用

    【鸿蒙专栏,从入门到实战系列】:https://bbs.elecfans.com/user/4697363/posts/1. TextField组件基本用法组件说明:是Text的子类,用来进行用户
    发表于 09-27 16:26

    ZVIT光伏玻璃原片表面在线检测系统主要由哪几个部分构成

    光伏玻璃原片表面在线检测系统工作原理是什么?ZVIT光伏玻璃原片表面在线检测系统主要由哪几个部分构成
    发表于 10-22 06:07

    STM32最小系统主要是由哪些部分构成

    STM32最小系统主要是由哪些部分构成的?有没有哪位大神分享一下啊
    发表于 11-23 07:34

    单片机主要由哪几部分构成

    单片机主要由运算器、控制器和寄存器三大部分构成。其中,运算器由算术逻辑单元(ALU)、累加器、寄存器等构成,首先累加器和寄存器向ALU输入两个8位源数据,其次ALU完成源数据的逻辑运算
    发表于 12-01 06:18

    NodeMCU+Influxdb+Grafana主要由哪几部分构成

    电力计量——NodeMCU+Influxdb+Grafana主要由一下几个部分构成:-数据库:Influxdb——开源的时序数据库 -前端:Grafana——开源的图表展示 -数据采集
    发表于 02-16 06:42

    TextField组件的相关资料分享【使用方法+案例】

    目录  1.TextField组件基本用法  2. 获取文本输入提示的内容并进行Toast  3.TextField组件高级使用  3.1 密码的密文展示  3.2 收藏的设置  3.3 气泡的设置
    发表于 03-29 14:56

    MATLAB信号处理详解_部分3

    MATLAB信号处理详解第三部分 有需要的可以参考下
    发表于 12-24 14:04 10次下载

    HarmonyOS系统TextField组件基本用法

    1. TextField组件基本用法 组件说明: 是Text的子类,用来进行用户输入数据的 常见属性: 《TextField ohos:id=“$+id:text” ohos:height
    的头像 发表于 10-09 09:18 1436次阅读
    HarmonyOS系统<b class='flag-5'>TextField</b>组件基本用法

    TextField被填充提示将标签浮现在上方

    项目介绍: 项目名称:floatlabelededittext 所属系列:openharmony的第三方组件适配移植 功能:使用一个子TextField,当TextField被填充时,提示将浮现
    发表于 03-18 15:10 1次下载
    <b class='flag-5'>TextField</b>被填充提示将标签浮现在上方

    pcb线路板主要部分组成

      一站式PCBA智造厂家今天为大家讲讲pcb由哪些部分组成成型?pcb线路板的构成部分及作用。PCB是由各种不同的层组成的,不同的层有不同的用途和意义,为方便大家更好的理解PCB的组成,接下来为大家
    的头像 发表于 05-17 09:46 2860次阅读