微信小程序开发——Skyline中Worklet动画

Skyline简单介绍

Skyline是微信小程序的新的渲染引擎,其相比于Webview引擎拥有更好的性能,同时也支持更多原生的新特性,比如Worklet动画、路由跳转的转场动画、共享元素动画、全局工具栏等,这些新特性都可以让小程序拥有更加丝滑的操作,以及转场。小编在此非常推荐大家去使用Skyline进行自己的小程序开发。

Skyline目前支持按页面去升级,也就是部分页面可以继续使用Webview,部分可以使用Skyline,具体的配置方法可以参考官方文档:Skyline 渲染引擎 / 从 WebView 迁移 / 起步

本文主要介绍如何使用Skyline的Worklet动画,让你的小程序交互性能更加流畅。

Skyline的线程模型

在讲Worklet动画之前,我们先了解下Skylilne的线程模型。不同于Webview的单线程模型,Skyline改成了双线程模型,将js逻辑、DOM树构建,CSS样式计算单独放到了AppService线程,简称JS线程,而应用样式、布局(Layout)和绘制(Paint)则放在一个渲染线程,简称UI线程,以下是其架构图:

分开成两个线程后,当有需要在JS线程计算动画的过程,而在UI线程进行展示,两者直接很难去协调同步,容易出现动画不流畅的问题。因此微信小程序就提供了Worklet动画来解决这个问题。

什么是Worklet动画

Worklet动画有两个核心概念,分别是Worklet函数,和Worklet共享变量。

Worklet函数

Worklet函数就是一种既可以在JS线程中运行,也可以在UI线程中运行的函数。

Worklet函数的定义就是在函数的顶部加上'worklet'字符串标志:

scss 复制代码
function someWorklet(greeting) {
  'worklet';
  console.log(greeting);
}

// 运行在 JS 线程
someWorklet('hello') // print: hello

// 运行在 UI 线程
wx.worklet.runOnUI(someWorklet)('hello') // print: [ui] hello

Worklet函数间可以直接相互调用:

javascript 复制代码
const name = 'worklet1'

function anotherWorklet() {
  'worklet';
  return 'hello ' + name;
}

// worklet 函数间可互相调用
function someWorklet() {
  'worklet';
  const greeting = anotherWorklet();
  console.log('another worklet says ', greeting);
}

wx.worklet.runOnUI(someWorklet)() // print: [ui] another worklet says hello worklet1

Worklet函数通过wx.worklet.runOnJS来调用普通函数:

scss 复制代码
function someFunc(greeting) {
  console.log('hello', greting);
}

function someWorklet() {
  'worklet'
  // 访问非 worklet 函数时,需使用 runOnJS
  // someFunc 运行在 JS 线程
  wx.worklet.runOnJS(someFunc)('js function')
}

wx.worklet.runOnUI(someWorklet)() // print: hello js function

需要注意的是,Worklet函数不能直接调用普通的函数,需要通过wx.worklet.runOnJS来运行普通的函数,让其在JS线程中运行。

Worklet共享变量

Worklet共享变量就是在JS线程中创建,并且可以在JS线程和UI线程中共享使用的变量。

scss 复制代码
const { shared, runOnUI } = wx.worklet

const offset = shared(0)
function someWorklet() {
  'worklet'
  console.log(offset.value) // print: 1
  // 在 UI 线程修改
  offset.value = 2
  console.log(offset.value) // print: 2
}
// 在 JS 线程修改
offset.value = 1

runOnUI(someWorklet)()

Worklet的实际使用场景

我们结合下前两节的Worklet函数和Worklet共享变量,看下在实际的使用场景。我们开头提到过,Worklet动画解决的就是动画函数在JS线程和UI线程之间协调时导致的卡顿问题。那么我们来看看这个问题是如何使用Worklet动画去解决的。

驱动动画

bash 复制代码
<view id="moved-box"></view>
<view id="btn" bind:tap="tap">点击驱动小球移动</view>
javascript 复制代码
Page({
  onLoad() {
    const offset = wx.worklet.shared(0)
    this.applyAnimatedStyle('#moved-box', () => {
      'worklet';
      return {
        transform: `translateX(${offset.value}px)`
      }
    })
    this._offset = offset
  },
  tap() {
    // 点击时修改 sharedValue 值,驱动小球移动
    this._offset.value = Math.random()
  }
})

当点击按钮 #btn 时,我们用随机数给 offset 进行赋值,小球会随之移动。

applyAnimatedStyle 接口的第二个参数 updater 为一个 worklet 函数,其捕获了共享变量 offset,当 offset 的值变化时,updater 会重新执行,并将返回的新 styleObject 应用到选中节点上。

当然,光看这个例子,跟用 setData 看好像没有什么区别。但当 worklet 动画和手势结合时,就产生了质变。

结合手势系统

ini 复制代码
<pan-gesture-handler onGestureEvent="handlepan">
  <view class="circle"></view>
</pan-gesture-handler>
ini 复制代码
Page({
  onLoad() {
    const offset = wx.worklet.shared(0);
    this.applyAnimatedStyle('.circle', () => {
      'worklet';
      return {
        transform: `translateX(${offset.value}px)`
      };
    });
    this._offset = offset;
  },
  handlepan(evt) {
    'worklet';
    if (evt.state === GestureState.ACTIVE) {
      this._offset.value += evt.deltaX;
    }
  }
});

当手指在 circle 节点上移动时,会产生平滑的拖动效果。handlepan 回调触发在 UI 线程时修改了 offset 的值,而offset值改变的时候会触发this.apppAnimatedStyle的updated函数,并修改.circle的style的transform的值,触发了circle 节点的移动,整个过程都是在UI线程中进行,没有JS线程和UI线程的切换,从而让动画更加的平滑顺畅。

手势系统中的回调handlepan必须是Worklet函数

关于手势系统,我们会在接下来的文章中详细介绍。

相关推荐
每天开心2 小时前
噜噜旅游App(4)——构建旅游智能客服模块,实现AI聊天
前端·微信小程序·前端框架
老华带你飞8 小时前
口腔助手|口腔挂号预约小程序|基于微信小程序的口腔门诊预约系统的设计与实现(源码+数据库+文档)
java·数据库·微信小程序·小程序·论文·毕设·口腔小程序
尸僵打怪兽8 小时前
HBuilder X打包发布微信小程序
微信小程序·小程序·打包·hbuilder x
半生过往18 小时前
微信小程序文件下载与预览功能实现详解
微信小程序·小程序·notepad++·压缩包下载解压
源码_V_saaskw18 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
996幸存者1 天前
uni-app区域选择、支持静态、动态数据
微信小程序·uni-app
ᥬ 小月亮1 天前
Uniapp编写微信小程序,绘制动态圆环进度条
微信小程序·小程序·uni-app
The_era_achievs_hero1 天前
UniappDay03
vue.js·微信小程序·uni-app
Python大数据分析2 天前
uniapp之微信小程序标题对其右上角按钮胶囊
微信小程序·小程序·uni-app
The_era_achievs_hero3 天前
uni-appDay02
javascript·vue.js·微信小程序·uni-app