作者: AlexZhang
基于 4 月 16 日到 4 月 20 日的讨论和一周内PR 进行总结。
本周是富有成效的一周,本周 Makepad 团队在多个方面取得了进展,包括平台特性、核心控件的修复与改进、性能优化以及底层渲染架构的调整。
关键进展包括解决了 iOS 平台上的手势交互难题、修复了 Dock 状态加载的核心 Bug、推进了 Android XR 的底层支持。同时,团队也在持续进行性能分析与优化(文本、字体栈),并修复各种控件和平台相关的问题。对 CI 的规划也预示着未来开发流程的改进。一些已知的小问题(如 PortalList 警告、Html 链接解析)已被识别并等待后续处理。
UIGestureRecognizer
在识别手势后会“接管”事件流,阻止底层视图(Makepad 的 MTKView)接收后续的触摸事件(如 FingerUp
),直到手势完全结束(手指抬起)。这给在手势进行中(手指未抬起但长按已满足条件)触发 Makepad 内部事件带来了困难。cancelsTouchesInView
属性为 false
解决了这个问题,允许底层视图在手势识别后继续接收触摸事件。Dock 状态加载 Bug 修复 (#711):
LiveId
计数器重置,可能导致动态创建的 Splitter 或 Tab 的 ID 与加载的 ID 冲突,从而覆盖旧布局。load_state
时,将加载进来的、原先是唯一 ID 的 LiveId
转换为基于字符串的新 LiveId
,避免了冲突。Kevin 请求 Rik 对此方案进行了审查。PortalList / DrawList 问题:
smooth_scroll_to_end
函数得到改进,现在内部调用 smooth_scroll_to
(#691)。DrawListId
生成索引错误的警告,该警告在使用不同模板渲染相同 item_id
的 PortalList
时出现。虽然目前看起来不影响功能,但团队讨论了调试方法(panic、#[track_caller]
)以追踪来源。Button 状态 Bug 修复 (#718):
CommandTextInput 改进:
Html Widget 链接解析问题 (Kevin):
<Html>
控件在处理嵌套在其他标签(如 <code>
)内的自定义子控件(如 <a>
)时,链接内容无法正确解析和渲染。初步判断是 <Html>
控件对子控件内容处理方式的问题,而非底层 HTML 解析器的问题。cargo makepad check all
检查。Makepad 的事件系统(如 Hit
枚举)中使用了 FingerDown
, FingerUp
, FingerHoverIn
等术语来描述触摸和鼠标交互。
讨论点:
Rik 提到,未来可能需要考虑非人类用户(比如 AI 或“长着触手的异形霸主” - 这是一种幽默的说法)与 UI 交互的可能性。在这种情况下,“finger”(手指)这个词可能就不太合适了。Rik 指出,Web 标准制定组织 W3C 使用了更通用的术语 "pointer"(指针)来涵盖鼠标、触摸、笔等各种输入方式。他认为 W3C 在这方面考虑得更周全。
结论 (推测):
虽然没有明确决定立即修改,但讨论表明团队意识到了 "finger" 的局限性,并认可 "pointer" 作为更通用、更具未来兼容性的术语的价值。这可能意味着未来 Makepad 的事件系统可能会向 "pointer" 事件迁移,以更好地适应多样化的输入和交互方式。
NIH 综合症,即“非我发明综合症”,是一种文化或组织现象,指的是开发者或组织倾向于避免使用、信任或购买来自外部(第三方)的现有产品、研究、标准或知识,即使它们是现成可用且可能更优的解决方案,而倾向于自己重新开发或“重新发明轮子”。
讨论中的体现:
Kevin 在处理 iOS 手势识别器时遇到了困难,因为苹果提供的 UIGestureRecognizer 行为复杂且有些“霸道”(会阻止事件传递给底层视图)。他担心可能需要自己从头实现一个手势识别器来获得所需的控制权。
Rik 表达了对必须自己实现底层功能的担忧(“the hard cost of NIH”),但也强调了 Makepad 的一个优势:如果现有的(苹果的)方案无法满足需求,他们 可以 选择自己实现(“atleast we CAN choose”, “cherish the thought that we CAN”)。他将此与 Web 开发进行对比,Web 开发者通常受限于浏览器提供的 API,无法自行修改底层行为(“on web you cant choose”)。
Kevin 承认自己也有 NIH 倾向(“I too suffer from NIH syndrome”),因为他过去曾开发过自己的操作系统。但他认为手势识别这种相对高层的功能 不应该 属于必须自己重新发明的范畴,暗示苹果应该提供更好的 API 或定制性。
这段讨论反映了开发者在面对外部平台或库的限制时的常见困境:
Makepad 的立场 (推测):
讨论表明 Makepad 团队倾向于在可能的情况下利用平台提供的功能,但保留在必要时进行底层定制甚至重新实现的能力,以确保最终的用户体验和框架的灵活性。他们认识到 NIH 的成本,但也将“能够选择自研”视为一种优势。
总的来说,NIH 综合症描述了一种“闭门造车”的心态,而 Makepad 团队在讨论中展现了对这种心态的警惕,同时也珍视在必要时进行自主开发的自由度。
苹果的 UIGestureRecognizer
是一套强大的框架,用于识别用户在触摸屏上的各种手势,如点击 (Tap)、长按 (Long Press)、平移 (Pan)、捏合缩放 (Pinch)、旋转 (Rotation) 和轻扫 (Swipe)。
它的核心思想是:
UIView
上。UITouch
对象,包含触摸的开始、移动、结束、取消等信息)。Possible
: 初始状态,手势可能发生。Began
: 手势已经开始(例如,长按已达到足够时间,或平移已移动足够距离)。Changed
: 手势正在进行中且状态发生变化(例如,手指正在平移或捏合)。Ended
/ Recognized
: 手势成功完成(例如,手指抬起完成了一次点击或平移)。Cancelled
: 手势被系统或其他手势识别器取消。Failed
: 触摸序列不符合手势要求。“接管事件流”的行为 (默认情况)
对话中提到的关键行为是 UIGestureRecognizer
默认会“接管”事件流。具体来说:
touchesBegan:
, touchesMoved:
, touchesEnded:
等方法)。Began
或 Recognized
/Ended
),默认情况下,它会阻止后续的原始触摸事件传递给该视图及其子视图。 这就是 Kevin 提到的“take over the event flow and do not allow the underlying view to receive future events”。cancelsTouchesInView
属性的作用
Kevin 后来发现的 cancelsTouchesInView
属性是解决上述问题的关键。
cancelsTouchesInView = true
(默认值): 当手势被识别时,所有当前正在进行的触摸事件会被标记为“取消”(发送 touchesCancelled:
消息给视图),并且后续的触摸事件将不再传递给视图,直到这个手势结束。这就是导致 Makepad 底层视图收不到 FingerUp
等事件的原因。cancelsTouchesInView = false
: 当手势被识别时,触摸事件仍然会继续传递给视图。这意味着视图的 touchesBegan:
, touchesMoved:
, touchesEnded:
等方法仍然会被调用,即使手势识别器也在同时处理这些触摸。为什么设置 cancelsTouchesInView = false
对 Makepad 很重要?
Makepad 有自己的事件处理系统,它需要接收完整的触摸事件序列(按下、移动、抬起)来驱动其内部的 Hit
检测和 Widget 事件分发逻辑。如果 iOS 的手势识别器在识别手勢(如长按)后就拦截了后续的 touchesEnded
事件,Makepad 就无法知道手指何时抬起,导致无法触发对应的 FingerUp
事件,进而可能导致 UI 状态不一致或交互中断。
通过将 cancelsTouchesInView
设置为 false
,Kevin 允许 Makepad 的底层视图(MTKView
)即使在长按手势被 iOS 识别后,也能继续接收到原始的触摸事件(包括手指抬起的事件),从而能够正确地生成和处理 Makepad 内部的 FingerUp
事件。
苹果的 UIGestureRecognizer
是一个强大的状态机,用于识别复杂手势。其默认行为是在识别手势后“接管”并取消传递给视图的原始触摸事件,以简化交互逻辑。然而,对于像 Makepad 这样拥有自己完整事件系统的框架,这种默认行为会造成干扰。通过设置 cancelsTouchesInView = false
,可以允许原始触摸事件继续传递给底层视图,使得 Makepad 能够接收并处理完整的用户交互序列。