返回介绍

简介

发布于 2020-01-01 19:51:28 字数 3844 浏览 1936 评论 0 收藏 0

BindingX 是解决weexReact Native上富交互问题的一种解决方案。

它提供了一种称之为 "Expression Binding" 的机制可以在 weexReact Native 上让手势等复杂交互操作以60fps的帧率流畅执行,而不会导致卡顿,因而带来了更优秀的用户体验。

背景

(可翻译为: Why is this challenging) 由于 weex底层使用的 JS-Native Bridge 具有天然的异步特性,这使得 JSNative 之间的通信会有固定的性能损耗,因此在一些复杂的交互场景中,JS 代码很难以高帧率运行。举个例子,如果我们要实现 "视图随手势移动" 的效果,那么按照传统的方式,需要在这个视图上绑定 touch 或者 pan 事件,当手势发生时, Native 会将手势事件通过 Bridge 传递给 JS , 这产生了一次 NativeJS 的通信。而 JS 在接收到事件后,需要根据手指移动的偏移量驱动界面变化,这又会产生一次 JSNative 的通信。与此同时,手势回调事件触发的频率是非常高的,频繁的的通信带来的时间成本很可能导致界面无法在16ms中完成绘制,进而产生卡顿。

事实上,不仅仅是在 weex 上存在这种问题, React Native 等框架同样存在类似的问题。拿 React Native Animated 组件为例,为了实现流畅的动画效果,这个组件采用了声明式的API,在 JS 端仅仅定义了输入与输出以及具体的 transform 行为,而真正的动画是通过 Native DriverNative 层执行,这样就避免了频繁的通信。然而,这个方案只能解决一部分问题,如果是有复杂交互操作的场景就不够用了。另外,声明式的方式能够定义的行为非常有限,无法满足更复杂的交互场景。

原理介绍

我们通过探索,提出了一种全新的方式用来解决这个问题,方案称之为 Expression Binding 。 还是拿 "视图随手势移动" 这个场景举例。我们的方案是这样的:

在手势开始前, JS 将具体的手势控制行为以 "表达式" 的方式传递给 Native ,我们定义了两个变量 xy ,分别代表手势过程中横向和纵向的偏移量。 那么"跟手移动"的表达式应该是这样的:

(伪代码)

f(x) = x
f(y) = y

另外,我们最终希望改变的是 "某视图"的 translateXtranslateY 属性,那么我们同时再把"期望改变的属性"和"某视图"的引用(anchor)也传递给 Native ,像这样:

(伪代码)

{
   
   anchor: foo_view.ref                    // ----> 这是"产生手势的视图"的引用  
   props:
            [
                {
                    element: foo_view.ref, // ----> 这是"期望改变的视图"的引用
                    expression: f(x) = x,  // ----> 这是具体的表达式
                    property: translateX   // ----> 这是期望改变的属性
                },
                {
                    element: foo_view.ref,
                    expression: f(y) = y,  // ----> y 属性
                    property: translateY
                }
            ]
}

您可能注意到在上面这段伪代码中,"视图的引用" (foo_view.ref)被传递了两次,这是因为 "产生手势的视图" 和 "期望改变的视图" 并不总是同一个。 比如说,你希望在视图A上滑动,而改变的是视图B的位置。因此,我们进行了区分,这样会更加通用。另外,正如上面说的,我们通过一个数据集合(即 elementexpressionproperty )来描述 "视图" 的行为。因为手势可能会伴随着视图多个属性的变换,所以props中可以传递一个数组。

当这份配置传递到 Native 后, Native 会对目标视图( anchor )设置手势事件监听器。当手指在屏幕上移动时,监听器会收到回调事件。紧接着, Native 会直接根据其内置的 表达式解析引擎 去解释执行表达式,并根据表达式执行的结果驱动视图变换。比如手势横向滑动 60px 纵向滑动 70px ,那么表达式 f(x)=xf(y)=y 的结果分别是 60 和 70,再根据对应的属性 translateXtranslateY 就可以对视图进行平移了。 整个过程不再需要和 JS 端进行通信,因此用户体验如丝般顺滑。

以上就是这套方案的基本原理。一句话总结:

BindingX 的核心思想就是将"交互行为"以表达式的方式描述,并提前预置到Native,避免在行为触发时JS与native的频繁通信。

事实上, BindingX 解决的不仅仅是手势交互问题,理论上任何 "频繁通信+UI更新" 的场景都可以使用这套方案。 BindingX 目前支持已经以下四种场景:

  • 监听 pan 手势,更新UI。

  • 监听滚动容器(如List)的onscroll事件,更新UI。

  • 监听设备传感器方向变化,更新UI。

  • 动画。(即监听设备的每一帧的屏幕刷新回调事件,更新UI)。

平台支持

BindingX 通过插件的形式同时支持React Native和weex。在weex上,可以作为一个 weex 模块 直接注册到weex环境中, 在 JS 层同时支持 weex DSLRax DSL 。在 React Native 上,也可以以类似的方式使用。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文