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

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

3天内不再提示

Flutter 3.3 之 SelectionArea 好不好用?用 "Bug" 带您全面了解它 | 开发者说·DTalk

谷歌开发者 来源:未知 2022-11-10 11:35 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群


本文原作者: 恋猫de小郭,原文发布于:GSYTech


随着 Flutter 3.3 正式版发布,Global Selection 终于有了官方的正式支持,「该功能补全了 Flutter 长时间存在 Selection 异常等问题,特别是在 Flutter Web 下经常会有选择文本时与预期的行为不匹配的情况」



使用


「使用 SelectionArea 也十分简单,如下代码所示,只需要在您想要支持的地方添加 SelectionArea 即可」,甚至可以在每个路由下的Scaffold 添加SelectionArea 来全面启用支持。

默认情况下SelectionArea 已经实现了所有常见的功能,并且 Flutter 针对不同平台进行了差异化实现,如下图所示 AndroidiOS 会有不同的样式效果。





「当然,也许这时候您会发现在 iOS 上的 Toolbar 居然没有全选」,其实这是因为 iOS 使用了 TextSelectionControls 默认的 canSelectAll 判断,这个判断里有一个条件就是需要 selection 的 start == end 才符合条件。

所以如果您觉得这个判断有问题,完全可以自己 override 一个自定义的 TextSelectionControls,比如在canSelectAll 直接 return true





是的,「对于SelectionArea 我们可以通过继承 TextSelectionControls 来自定义」:

  • 通过 buildToolbar 自定义弹出的 Toolbar 样式和逻辑,甚至您可以添加一些额外的标签能力,比如 "插入图片";
  • 通过 buildHandle 自定义 Selection Handle 可拖动部分的样式。

而在SelectionArea 里,不管是 Handle 还是 Toolbar,都是通过新增 Overlay 来实现样式,这部分的逻辑主要在 SelectionOverlay 对象:






如果您还不了解Overlay,可以简单理解为:「默认情况下所有的路由页面都在一个 Overlay 下,打开一个 Route 就是添加一个 OverlayEntryOverlay 里」

所以 Handle 和 Toolbar 都是通过OverlayEntry 打开的特殊 "路由" 控件,拥有新的层级,例如下方右图就是 Toolbar 所在的OverlayEntry







「另外,对于 Handle 的颜色定义,默认情况下主要来自 TextSelectionThemeTheme


例如MaterialTextSelectionControls 里,start 和 end 两个 Handle 的颜色,默认是通过 TextSelectionThemeselectionHandleColor 或者Themeprimary 来设置。

那文字的选中区域的颜色是怎么来的?难道也是 OverlayEntry 吗?

答案是否定的,这部分颜色主要是来自于文本绘制时 Canvas 的渲染。

如下代码所示,「当文本被绘制时,会判断当前是否有被选中的片段,如果存在选中的片段,会调用绘制对应的选中图层」

而对于文字的选中区块的颜色,默认是通过 DefaultSelectionStyleselectionColor 来显示,当然,如下第二张图所示,在 MaterialApp 里它依然和 TextSelectionThemeselectionColor 或者Themeprimary 有关系。

「那如果您还想要在SelectionArea 下的某些内容不允许被选中呢」


这里 Flutter 提供了 SelectionContainer.disabled 实现,只要在对应内容嵌套 SelectionContainer.disabled,那么这部分内容下的文本就无法被选中。



为什么嵌套SelectionContainer.disabled 就可以禁用文本选中的能力?这其实和SelectionArea 的实现有关系:


SelectionContainer 内部实现了一个 InheritedWidget,它会往下共享一个 SelectionRegistrar,而默认情况下SelectionArea 内部使用了SelectionContainer 并且往下共享了对应的 Registrar 实现。


  • SelectionArea 内部的 SelectionContainer 是有对应的 registrar 实现往下共享;
  • SelectionContainer.disabled 内部的registrarnull

「所以根本区别就在于 SelectionContainer.disabled 里没有 registrar,如下图一所示,加了 disabled 后获取到的 registrar 是 null,那么如下图二代码所示,在后续可选中区域的更新逻辑中就会直接 return。
△ 图一

图二

到这里您应该大致理解了如何使用和自定义一些 SelectionArea 的能力,那么接下来介绍两个 "Bug",通过这两个 "Bug" 我们深入理解SelectionArea 内部的实现情况。



问题 1


如下代码所示,「当使用了WidgetSpan 之后,默认情况下,用户在开始位置拖拽 Handle 进行选择时会无法选中WidgetSpan 里的文本」





PS:其实拖动可以选中,只是这里暂时以不能选中的情况下作为切入点。


为什么会这样?首先要知道,上面代码在使用了WidgetSpan 包裹 Hello World 之后,其实是存在两个 Text,也就是上述的 UI 是由两个 RenderParagraph 绘制完成。

那么对于最外层的 Text,其实它的文本内容是 "Flutter is the best!",注意这段文本,其实文本里此时是多了两个空格。
之所以会有这两个空格,其实是因为WidgetSpan 使用了 0xFFFC 的占位符,这段占位符在渲染时,就会被替换为WidgetSpan 对应的 Hello World 和猫头图片。

「那么这时候如果我们选择复制,复制出来的内容会是 Flutter isthe best!,中间的两个占位符是不会复制出来,因为在获取可选择片段时,会把对应的 placeholderCodeUnit 剔除。

另外,当我们点击复制的时候,WidgetSpan 所在的Hello World 并没有被选中,所以此时调用 getSelectedContent 就会得到 null,也就是没有内容。
所以可以看到: 此时在手动拖拽选择时,WidgetSpan 里的文本是不会被选中,因为它处于不同的 Text,对于外层 Text 而言它只是个占位符。


当然,「其实在拖动Handle还是可以选中WidgetSpan里的文本,比如您从HelloWorld开始拖动,这里拖动选中不了的原因后面会解释」


问题2


如果当我们点击了全选会怎么样?如下图所示,在我们点击全选之后,可以看到两个 "奇怪" 的问题:

  • WidgetSpan 里的 Hello World 可以被选中了;
  • 左侧的 Start Handle 位置不是在文本开头,而是在WidgetSpan 开始。

我们首先看第一点,「为什么点击全选时,WidgetSpan 里的 Hello World 可以被选中」


其实全选操作和拖拽 Handle 最大的不同就是: 它是往下直接发出全选事件 SelectAllSelectionEvent,而该事件会触发所有 child 响应事件,自然也就包括了 WidgetSpan 里的 Hello World

最后负责响应 SelectAll 事件的对象是 _SelectableFragment,这里主要有两个关键逻辑:
  • _handleSelectAll 获取得到 _textSelectionStart_textSelectionEnd,表明此时控件已经被选中;
  • didChangeSelection 里通过 paragraph.markNeedsPaint() 触发重绘,然后增加选中时的覆盖颜色。
可以看到,由于此时 WidgetSpan 里的 Hello World 也直接响应了全选事件,所以它会处于选中状态,这样之后在 getSelectedContent 调用里也可以获取到内容,也就是Hello World 能被复制出来。
**但是此时复制出来的内容会是 Hello World!Flutter isthe best! **,是不是感觉还不对?这就是我们要说的第二个问题,左侧的 Start Handle 位置不是在文本开头。

首先我们看,为什么复制出来之后的内容会是Hello World!Flutter isthe best!


正如前面说到的,复制调用的是 getSelectedContent 方法,如下代码所示,「可以看到在selectables 这个 List 的第一位就是Hello World,所以最终拼接出来的文本会是Hello World!Flutter isthe best!

那为什么 Hello World 会排在 selectables 的第一位?这就需要讲到 Flutter 里对 Selectable 的一个排序逻辑。

我们知道 Text 内部是通过 RenderParagraph 实现文本绘制,而RenderParagraph 在初始化的时候,「如果存在 _registrar,也就是存在SelectionArea 的时候,就会通过 add 把支持选中的片段添加 SelectionArea 内部的 _additions里。
之后 SelectionArea 内部会对可选中的内容进行排序,如下代码所示,在 sort 之前,此时的 Hello World_additions 列表的最末端,因为它处于 WidgetSpan 的 child 里,所以是最晚被加入到 _additions 的。
而在执行完 sort 之后,可以看到此时 Hello World 跑到了列表的最前面,「这也是为什么复制出来的内容顺序是Hello World 开头,然后 Start Handle 会显示在Hello World 的原因」
sort 的逻辑主要是通过compareOrder 实现,简单分析 compareOrder 的排序实现,可以看到其中有一个 _compareVertically 的逻辑,通过调试对比,「可以看到此时因为Hello World 所处的 Rect (top) 比其他文本高,所以它被认为是更高优先级的位置,类似于被误认为是上一行的情况」
知道了问题那就很好处理了,「如下代码所示,如果此时调整一下 WidgetSpan 的高度,可以看到全选逻辑下 Start Handle 正常了,但是.... End Handle 位置又不对了」





此时复制出来的内容会是 Flutter isthe best!Hello World!「因为这个时候会有一个很 "微妙" 的偏差值,导致 Hello World 排序时被排列到最后面」,从而导致 End Handle 不是预期的位置。
另外,这时候您会发现,如下左侧动图所示,「此时拖动 Handle 是可以选中 WidgetSpan 里的 Hello World,其实之前的情况下也可以,不过需要如右侧动图所示,需要从Hello World 开始拖动,「因为最开始的情况下 selectablesHello World 的排序层级更高,所以如果想要拖动选中,也需要从它开始」





目前这个问题在 master 和 stable 分支均可以复现,对应 issue 我也提交在#111021。


最后


虽然SelectionArea 的出现补全了 Flutter 的长久以来的短板之一,不过基于SelectionArea 实现的复杂程度,目前SelectionArea 还有不少的细节需要优化,但是万事开头难,本次 3.3 SelectionArea 的落地也算是一个不错的开始。


最后,相信通过本文大家应该对 SelectionArea 的使用和实现都有了一定的了解。



长按右侧二维码

查看更多开发者精彩分享




"开发者说·DTalk" 面向中国开发者们征集 Google 移动应用 (apps & games) 相关的产品/技术内容。欢迎大家前来分享您对移动应用的行业洞察或见解、移动开发过程中的心得或新发现、以及应用出海的实战经验总结和相关产品的使用反馈等。我们由衷地希望可以给这些出众的中国开发者们提供更好展现自己、充分发挥自己特长的平台。我们将通过大家的技术内容着重选出优秀案例进行谷歌开发技术专家 (GDE)的推荐。



 点击屏末||即刻报名参与"开发者说·DTalk"





原文标题:Flutter 3.3 之 SelectionArea 好不好用?用 "Bug" 带您全面了解它 | 开发者说·DTalk

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

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

    关注

    27

    文章

    6244

    浏览量

    110263

原文标题:Flutter 3.3 之 SelectionArea 好不好用?用 "Bug" 带您全面了解它 | 开发者说·DTalk

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

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    Flutter 移动端开发:集成淘宝 API 实现商品数据实时展示 APP

    在电商蓬勃发展的当下,移动端购物成为主流趋势。对于开发者而言,利用 Flutter 构建一个能够实时展示淘宝商品数据的 APP,既能满足用户便捷获取商品信息的需求,也能为电商业务拓展新的渠道
    的头像 发表于 11-13 09:36 163次阅读

    元服务发布配置开发者服务信息

    作为开发者的相关信息将面向元服务发布区域的用户公开,其中客服联系方式可能会提供给用户,用于咨询相关问题。 登录AppGallery Connect,点击“APP与元服务”。 选择要发布的元服务
    发表于 10-31 17:58

    电能质量在线监测装置在实际应用中如何选择有线或无线通信技术?

    电能质量在线监测装置选择有线或无线通信技术,核心是 **“先解决‘能不能用’,再优化‘好不好用’”**—— 以 “布线可行性” 为首要前提,再结合数据需求、环境特征、成本投入三维度综合判断,避免单纯依赖技术优劣选择。
    的头像 发表于 10-24 18:16 1994次阅读

    Android Studio中的Gemini全面支持Dart和Flutter开发

    在 Android Studio 中创建 Android 应用的 Flutter 开发者将迎来一次重大的飞跃: Android Studio 中的 Gemini 已全面支持 Dart
    的头像 发表于 08-06 13:52 1084次阅读
    Android Studio中的Gemini<b class='flag-5'>全面</b>支持Dart和<b class='flag-5'>Flutter</b><b class='flag-5'>开发</b>

    迅龙软件参加昇腾 AI 开发者创享日・广东站,为开发者打造沉浸式实操体验

    7月18日,线下顶尖人才汇聚的开发者盛会——昇腾AI开发者创享日・广东站在广州举行。活动以“创未来享非凡”为主题,聚焦广东本地产业特点,分享前沿AI创新技术,搭建生态交流平台,帮助开发者全面
    的头像 发表于 07-23 17:18 1102次阅读
    迅龙软件参加昇腾 AI <b class='flag-5'>开发者</b>创享日・广东站,为<b class='flag-5'>开发者</b>打造沉浸式实操体验

    华为正式启动HarmonyOS 6开发者Beta

    在2025年华为开发者大会(HDC)上,华为正式启动HarmonyOS 6开发者Beta,并全面展示一年多以来与合作伙伴共建鸿蒙生态的创新成果。
    的头像 发表于 06-24 15:42 645次阅读

    Flutter on Raspberry Pi:从入门到精通的完整指南!

    Flutter。通过遵循本文中概述的步骤,你将获得在树莓派上设置Flutter的知识和信心。无论你是初学者还是经验丰富的Flutter开发者,本指南都将确保你对过程有清晰的
    的头像 发表于 06-06 15:37 1369次阅读
    <b class='flag-5'>Flutter</b> on Raspberry Pi:从入门到精通的完整指南!

    阿童木双张检测器好不好用数据和场景说话

    在工业生产中,双张叠料检测是保障产线稳定与产品质量的关键环节。阿童木双张检测器凭借技术创新和行业落地经验,成为众多企业的选择。但它究竟“好不好用”?本文将从性能表现、场景适配、用户反馈三大维度展开
    的头像 发表于 05-22 11:39 614次阅读
    阿童木双张检测器<b class='flag-5'>好不好用</b>?<b class='flag-5'>用</b>数据和场景说话

    电子工厂ERP好不好用

    在电子制造业竞争日益激烈的当下,企业都在寻找提升效率、降低成本的解决方案,而ERP系统成为了众多企业的选择。那么,电子工厂ERP系统到底好不好用呢?本文将从多个实际应用场景出发,为你揭开答案。一
    的头像 发表于 05-12 09:58 492次阅读
    电子工厂ERP<b class='flag-5'>好不好用</b>

    开源mlops平台好用

    在MLOps平台的选择上,开源平台因其成本效益、灵活性以及社区支持等优势,受到了越来越多开发者和企业的青睐。那么,开源MLOps平台真的好用吗?下面,AI部落小编
    的头像 发表于 03-05 11:09 518次阅读

    云端AI开发者工具的核心功能

    当今,云端AI开发者工具已成为推动科技创新与行业升级的重要力量。那么,云端AI开发者工具有哪些核心功能呢?下面,AI部落小编深入探讨。
    的头像 发表于 02-28 11:46 870次阅读

    嵌入式软件工程师就业好不好?

    嵌入式软件工程师就业好不好?会不会越老越吃香?今天一起来看看。 首先看下市场需求。 随着物联网、人工智能、5G等前沿技术的快速发展,嵌入式系统的应用领域不断扩大,从智能家居、汽车电子到工业自动化
    发表于 02-20 10:19

    国外AI开发者平台好用

    当今,AI项目的复杂性和多变性给项目管理带来了前所未有的挑战。为了有效应对这些挑战,AI项目管理平台应运而生。那么,AI项目管理平台有什么?下面,AI部落小编了解
    的头像 发表于 02-19 10:16 580次阅读

    AI开发平台如何赋能开发者

    当下,AI开发平台通过提供丰富的工具集、优化的开发环境以及高效的部署能力,极大地降低了AI应用的开发门槛,加速了创新步伐。那么,AI开发平台如何赋能
    的头像 发表于 01-17 14:47 721次阅读

    嘉楠科技邀相约2024 RT-Thread开发者大会

    嘉楠科技(Canaan Inc.)(纳斯达克股票代码:CAN)将于12月21日,携旗下高性能端侧 AIoT 芯片产品及解决方案亮相上海2024 RT-Thread 开发者大会,全方位展示勘智芯片的具体能力及相关解决方案,务求让更多开发者在现场可以更深一步
    的头像 发表于 12-18 16:25 1294次阅读