欧美日韩精品一区二区在线线,一级无码在线收看,精品国产高清91,久久精品欧美电影

# 手勢(shì)系統(tǒng)

業(yè)務(wù)開(kāi)發(fā)中,我們常需要監(jiān)聽(tīng)節(jié)點(diǎn) touch 事件,處理拖拽、縮放相關(guān)邏輯。由于 Skyline 采用雙線程架構(gòu),在進(jìn)行這樣的交互動(dòng)畫(huà)時(shí),會(huì)具有較大的異步延遲,這點(diǎn)可以參考 wxs 響應(yīng)事件。

Skylinewxs 代碼運(yùn)行在 JS 線程,而事件產(chǎn)生在 UI 線程,因此 wxs 動(dòng)畫(huà) 性能有所降低,為了提升小程序交互體驗(yàn)的效果,我們內(nèi)置了一批手勢(shì)組件,使用手勢(shì)組件的優(yōu)勢(shì)包括

  1. 免去開(kāi)發(fā)者監(jiān)聽(tīng) touch 事件,自行計(jì)算手勢(shì)邏輯的復(fù)雜步驟
  2. 手勢(shì)組件直接在 UI 線程響應(yīng),避免了傳遞到 JS 線程帶來(lái)的延遲

# 效果展示

下圖演示了使用手勢(shì)、協(xié)商手勢(shì)實(shí)現(xiàn)的拖動(dòng)小球,半屏彈窗手勢(shì)拖動(dòng)關(guān)閉,分段半屏等效果。點(diǎn)擊查看更多 Skyline 示例。

掃碼小程序示例,分別體驗(yàn) 基礎(chǔ)手勢(shì)協(xié)商手勢(shì) 新特性

# 手勢(shì)組件

組件名稱 觸發(fā)時(shí)機(jī)
<tap-gesture-handler> 點(diǎn)擊時(shí)觸發(fā)
<double-tap-gesture-handler> 雙擊時(shí)觸發(fā)
<scale-gesture-handler> 多指縮放時(shí)觸發(fā)
<force-press-gesture-handler> iPhone 設(shè)備重按時(shí)觸發(fā)
<pan-gesture-handler> 拖動(dòng)(橫向/縱向)時(shí)觸發(fā)
<vertical-drag-gesture-handler> 縱向滑動(dòng)時(shí)觸發(fā)
<horizontal-drag-gesture-handler> 橫向滑動(dòng)時(shí)觸發(fā)
<long-press-gesture-handler> 長(zhǎng)按時(shí)觸發(fā)

# 工作原理

手勢(shì)組件為虛組件,真正響應(yīng)事件的是其直接子節(jié)點(diǎn)。下方代碼中,我們給 container 節(jié)點(diǎn)添加了兩種類型的手勢(shì)監(jiān)聽(tīng)。

  1. 當(dāng)在屏幕上橫向滑動(dòng)時(shí),horizontal-drag 手勢(shì)節(jié)點(diǎn)的回調(diào)將被觸發(fā);
  2. 當(dāng)在屏幕上縱向滑動(dòng)時(shí),vertical-drag 手勢(shì)節(jié)點(diǎn)的回調(diào)將被觸發(fā)。
<horizontal-drag-gesture-handler>
  <vertical-drag-gesture-handler>
     <view id="container"></view>
  </vertical-drag-gesture-handler>
</horizontal-drag-gesture-handler>

觸摸屏幕時(shí),渲染引擎會(huì)從內(nèi)到外對(duì)手勢(shì)監(jiān)聽(tīng)器進(jìn)行手勢(shì)識(shí)別,當(dāng)某個(gè)手勢(shì)監(jiān)聽(tīng)器滿足條件時(shí),其余的手勢(shì)監(jiān)聽(tīng)器將會(huì)失效。如在 scroll-view 內(nèi)部添加縱向的手勢(shì)監(jiān)聽(tīng)時(shí),將會(huì)阻斷 scroll-view 內(nèi)的手勢(shì)監(jiān)聽(tīng)器,導(dǎo)致無(wú)法滑動(dòng)。

<scrol-view>
  <vertical-drag-gesture-handler>
     <view id="container"></view>
  </vertical-drag-gesture-handler>
</scroll-view>

需要注意的是,pan 類型的判定條件比 vertical-drag 要寬松,因此縱向滑動(dòng)時(shí),vertical-drag 將會(huì)響應(yīng),而 pan 則會(huì)失效。當(dāng)橫向滑動(dòng)時(shí),pan 類型則會(huì)響應(yīng)。

<vertical-drag-gesture-handler>
  <pan-gesture-handler>
     <view id="container"></view>
  </pan-gesture-handler>
</vertical-drag-gesture-handler>

# 通用屬性

屬性 類型 默認(rèn)值 必填 說(shuō)明
tag string 無(wú) 聲明手勢(shì)協(xié)商時(shí)的組件標(biāo)識(shí)
worklet:ongesture eventhandler 無(wú) 手勢(shì)處理回調(diào)
worklet:should-response-on-move callback 無(wú) 手指移動(dòng)過(guò)程中手勢(shì)是否響應(yīng)
worklet:should-accept-gesture callback 無(wú) 手勢(shì)是否應(yīng)該被識(shí)別
simultaneous-handlers Array<string> [] 聲明可同時(shí)觸發(fā)的手勢(shì)節(jié)點(diǎn)
native-view string 無(wú) 代理的原生節(jié)點(diǎn)類型

native-view 支持的枚舉值有 scroll-viewswiper。滾動(dòng)容器縱向滾動(dòng)時(shí),使用 <vertical-drag-gesture-handler> 手勢(shì)組件代理內(nèi)部手勢(shì),橫向滾動(dòng)時(shí),則使用 <horizontal-drag-gesture-handler>。

  • eventhandler 類型是事件回調(diào),無(wú)返回值
  • callback 類型是開(kāi)發(fā)者注冊(cè)到組件的回調(diào)函數(shù),會(huì)在適當(dāng)時(shí)機(jī)被執(zhí)行以讀取返回值
  • 所有的回調(diào)都只能傳入一個(gè) worklet 回調(diào)

# 事件回調(diào)參數(shù)

# worklet:should-response-on-move

返回的參數(shù) pointerEvent 各字段如下。每次觸摸移動(dòng)時(shí)進(jìn)行回調(diào),返回 false 時(shí),則對(duì)應(yīng)的手勢(shì)組件無(wú)法收到該次 move 事件。

屬性 類型 說(shuō)明
identifier number Touch 對(duì)象的唯一標(biāo)識(shí)符
type string 事件類型
deltaX number 相對(duì)上一次,X 軸方向移動(dòng)的坐標(biāo)
deltaY number 相對(duì)上一次,Y 軸方向移動(dòng)的坐標(biāo)
clientX number 觸點(diǎn)相對(duì)于可見(jiàn)視區(qū)左邊緣的 X 坐標(biāo)
clientY number 觸點(diǎn)相對(duì)于可見(jiàn)視區(qū)上邊緣的 Y 坐標(biāo)
radiusX number 返回能夠包圍接觸區(qū)域的最小橢圓的水平軸 (X 軸) 半徑
radiusY number 返回能夠包圍接觸區(qū)域的最小橢圓的垂直軸 (Y 軸) 半徑
rotationAngle number 返回一個(gè)角度值,表示上述由radiusX 和 radiusY 描述的橢圓為了盡可能精確地覆蓋用戶與平面之間的接觸區(qū)域而需要順時(shí)針旋轉(zhuǎn)的角度
force number 用戶對(duì)觸摸平面的壓力大小
timeStamp number 事件觸發(fā)的時(shí)間戳
Page({
  shouldResponseOnMove(pointerEvent) {
    'worklet'
    return false
  }
})

# worklet:should-accept-gesture

用法如下,框架手勢(shì)識(shí)別生效時(shí)進(jìn)行回調(diào),由開(kāi)發(fā)者決定手勢(shì)是否生效。以 Pan 手勢(shì)為例。

手指觸摸屏幕時(shí)進(jìn)入 State.Possible 狀態(tài),shouldAcceptGesture 返回 false 后進(jìn)入 State.CANCELLED 狀態(tài),返回 true 后進(jìn)入 State.Begin 狀態(tài),可繼續(xù)接收手續(xù) move 事件。

Page({
  shouldAcceptGesture() {
    'worklet'
    return false
  }
})

# worklet:ongesture

不同類型手勢(shì)組件返回的參數(shù)如下

# tap / double-tap

屬性 類型 說(shuō)明
state number 手勢(shì)狀態(tài)
absoluteX number 相對(duì)于全局的 X 坐標(biāo)
absoluteY number 相對(duì)于全局的 Y 坐標(biāo)

# pan / vertical-drag / horizontal-drag

屬性 類型 說(shuō)明
state number 手勢(shì)狀態(tài)
absoluteX number 相對(duì)于全局的 X 坐標(biāo)
absoluteY number 相對(duì)于全局的 Y 坐標(biāo)
deltaX number 相對(duì)上一次,X 軸方向移動(dòng)的坐標(biāo)
deltaY number 相對(duì)上一次,Y 軸方向移動(dòng)的坐標(biāo)
velocityX number 手指離開(kāi)屏幕時(shí)的橫向速度(pixel per second)
velocityY number 手指離開(kāi)屏幕時(shí)的縱向速度(pixel per second)

# scale

屬性 類型 說(shuō)明
state number 手勢(shì)狀態(tài)
focalX number 中心點(diǎn)相對(duì)于全局的 X 坐標(biāo)
focalY number 中心點(diǎn)相對(duì)于全局的 Y 坐標(biāo)
focalDeltaX number 相對(duì)上一次,中心點(diǎn)在 X 軸方向移動(dòng)的坐標(biāo)
focalDeltaY number 相對(duì)上一次,中心點(diǎn)在 Y 軸方向移動(dòng)的坐標(biāo)
scale number 放大或縮小的比例
horizontalScale number scale 的橫向分量
verticalScale number scale 的縱向分量
rotation number 旋轉(zhuǎn)角(單位:弧度)
velocityX number 手指離開(kāi)屏幕時(shí)的橫向速度(pixel per second)
velocityY number 手指離開(kāi)屏幕時(shí)的縱向速度(pixel per second)
pointerCount number 跟蹤的手指數(shù)
  • 多指滑動(dòng)時(shí),focalXfocalY 為多個(gè)觸摸點(diǎn)中心焦點(diǎn)的坐標(biāo)
  • 單指滑動(dòng)時(shí),pointerCount = 1,此時(shí)效果同 pan-gesture-handler,scale 手勢(shì)是 pan 的超集。

# long-press

屬性 類型 說(shuō)明
state number 手勢(shì)狀態(tài)
absoluteX number 相對(duì)于全局的 X 坐標(biāo)
absoluteY number 相對(duì)于全局的 Y 坐標(biāo)
translationX number 相對(duì)于初始觸摸點(diǎn)的 X 軸偏移量
translationY number 相對(duì)于初始觸摸點(diǎn)的 Y 軸偏移量
velocityX number 手指離開(kāi)屏幕時(shí)的橫向速度(pixel per second)
velocityY number 手指離開(kāi)屏幕時(shí)的縱向速度(pixel per second)

# force-press

屬性 類型 說(shuō)明
state number 手勢(shì)狀態(tài)
absoluteX number 相對(duì)于全局的 X 坐標(biāo)
absoluteY number 相對(duì)于全局的 Y 坐標(biāo)
pressure number 壓力大小

# 手勢(shì)狀態(tài)

所有手勢(shì) worklet:ongesture 回調(diào)均會(huì)返回一個(gè) state 狀態(tài)字段。

enum State {
  // 手勢(shì)未識(shí)別
  POSSIBLE = 0,
  // 手勢(shì)已識(shí)別
  BEGIN = 1,
  // 連續(xù)手勢(shì)活躍狀態(tài)
  ACTIVE = 2,
  // 手勢(shì)終止
  END = 3,
  // 手勢(shì)取消
  CANCELLED = 4,
}

我們將手勢(shì)分為如下兩種類型:

  1. 離散手勢(shì):tapdouble-tap,僅觸發(fā)一次
  2. 連續(xù)手勢(shì):其它類型的手勢(shì)組件,隨手指拖動(dòng)會(huì)觸發(fā)多次

tap-gesture-handler 手勢(shì)組件返回的 state 始終為 1。

pan-gesture-handler 手勢(shì)組件在一個(gè)完整的拖動(dòng)過(guò)程中,state 會(huì)按如下方式改變

  1. 手指剛接觸屏幕時(shí),state = 0
  2. 移動(dòng)一小段距離,pan 手勢(shì)判定生效時(shí),state = 1
  3. 繼續(xù)移動(dòng),state = 2
  4. 手指離開(kāi)屏幕 state = 3

由于嵌套的手勢(shì)會(huì)產(chǎn)生沖突(僅有一個(gè)最終判定識(shí)別生效),因此連續(xù)手勢(shì) state 的變化可能有如下一些情景,開(kāi)發(fā)者需要根據(jù) state 值來(lái)處理一些異常情況。

  1. POSSIBLE -> BEGIN -> ACTIVE -> END 正常流程
  2. POSSIBLE -> BEGIN -> ACTIVE -> CANCELLED 提前中斷
  3. POSSIBLE -> CANCELLED 手勢(shì)未識(shí)別

并不是所有的連續(xù)手勢(shì)均有 POSSIBLE 狀態(tài),如 scale-gesture-handler 手勢(shì)組件,當(dāng)雙指觸摸后松手,state 變化如下:

  1. 雙指觸摸屏幕,state = 1, pointerCount = 2
  2. 雙指放大操作,state = 2, pointerCount = 2
  3. 雙指離開(kāi)屏幕,state = 3, pointerCount = 1,之后會(huì)相繼回調(diào) a. state = 1, pointerCount = 1 b. state = 2, pointerCount = 1 c. state = 3, pointerCount = 0

# 注意事項(xiàng)

  • 手勢(shì)組件僅在 Skyline 渲染模式下才能使用
  • 手勢(shì)組件為虛組件,不會(huì)進(jìn)行布局,手勢(shì)組件上設(shè)置 styleclass 是無(wú)效的
  • 手勢(shì)組件僅能含有一個(gè)直接子節(jié)點(diǎn),否則不生效
  • 手勢(shì)組件的父組件樣式會(huì)直接影響其子節(jié)點(diǎn)
  • 手勢(shì)組件的回調(diào)函數(shù)均需聲明為 worklet 函數(shù)
  • 手勢(shì)不同于普通 touch 事件,不會(huì)進(jìn)行冒泡
  • 手勢(shì)組件的 eventhandler / callback 均需聲明為 worklet 函數(shù),回調(diào)在 UI 線程觸發(fā)

# 使用方法

# 示例代碼

在開(kāi)發(fā)者工具中預(yù)覽效果

# Chaining API init 函數(shù)示例代碼

在開(kāi)發(fā)者工具中預(yù)覽效果

# 示例一:監(jiān)聽(tīng)拖動(dòng)手勢(shì)

<pan-gesture-handler on-gesture-event="handlePan">
  <view></view>
</pan-gesture-handler>
Page({
  handlePan(evt) {
    "worklet";
    console.log(evt.translateX);
  },
});

# 示例二:監(jiān)聽(tīng)嵌套的手勢(shì)

<horizontal-drag-gesture-handler on-gesture-event="handleHorizontalDrag">
  <vertical-drag-gesture-handler on-gesture-event="handleVerticalDrag">
    <view class="circle">one-way drag</view>
  </vertical-drag-gesture-handler>
</horizontal-drag-gesture-handler>

# 示例三:代理原生組件內(nèi)部手勢(shì)

對(duì)于 <scroll-view><swiper> 這樣的滾動(dòng)容器,內(nèi)部也是基于手勢(shì)來(lái)處理滾動(dòng)操作的。相比于 webskyline 提供了更底層的訪問(wèn)機(jī)制,使得在做一些復(fù)雜交互時(shí),可以做到更細(xì)粒度、分階段的控制。

<vertical-drag-gesture-handler
  native-view="scroll-view"
  should-response-on-move="shouldScrollViewResponse"
  should-accept-gesture="shouldScrollViewAccept"
  on-gesture-event="handleGesture"
>
  <scroll-view
    scroll-y
    type="list"
    adjust-deceleration-velocity="adjustDecelerationVelocity"
    bindscroll="handleScroll"
  >
    <view class="item" wx:for="{{list}}">
      <view class="avatar" />
      <view class="comment" />
    </view>
  </scroll-view>
</vertical-drag-gesture-handler>

以縱向滾動(dòng)的 <scroll-view> 為例,可使用 <vertical-drag-gesture-handler> 手勢(shì)組件,并聲明 native-view="scroll-view" 來(lái)代理其內(nèi)部手勢(shì)。

# 滾動(dòng)事件

當(dāng)滾動(dòng)列表時(shí),手勢(shì)組件的事件回調(diào)和 <scroll-view>scroll 事件回調(diào)均會(huì)觸發(fā),它們的區(qū)別在于:

  1. scroll 事件僅在滾動(dòng)時(shí)觸發(fā),當(dāng)觸頂/底后,不再回調(diào)
  2. on-gesture-event 手勢(shì)回調(diào)當(dāng)手指在屏幕上滑動(dòng)時(shí)會(huì)一直觸發(fā),直到松手

# 手勢(shì)控制

在前面介紹連續(xù)手勢(shì)狀態(tài)時(shí),我們知道手勢(shì)有自身的識(shí)別過(guò)程。例如 vertical-drag 手勢(shì),當(dāng)手指觸摸時(shí)為 POSSIBLE 狀態(tài),移動(dòng)一小段距離后才識(shí)別為 BEGIN 狀態(tài),此時(shí)稱手勢(shì)被識(shí)別(ACCEPT)。

# 1. 手勢(shì)識(shí)別

should-accept-gesture 屬性允許開(kāi)發(fā)者注冊(cè)一個(gè) callback,并返回一個(gè)布爾值,參與到手勢(shì)識(shí)別的過(guò)程。當(dāng)返回 false 時(shí),本次觸摸手勢(shì)不再生效,相關(guān)聯(lián)的 <scroll-view> 組件也無(wú)法滾動(dòng)。

# 2. 事件派發(fā)

should-response-on-move 屬性允許開(kāi)發(fā)者注冊(cè)一個(gè) callback,并返回一個(gè)布爾值,參與到事件派發(fā)的過(guò)程。當(dāng)返回 false 時(shí),當(dāng)次 move 的事件不再派發(fā),相關(guān)聯(lián)的 <scroll-view> 不繼續(xù)滾動(dòng)。該回調(diào)在手指移動(dòng)過(guò)程中會(huì)持續(xù)觸發(fā),可隨時(shí)改變,進(jìn)而控制滾動(dòng)容器繼續(xù)/暫停滾動(dòng)。

Page({
  // 這里返回 false,則 scroll-view 無(wú)法滾動(dòng)
  // should-accept-gesture 會(huì)在手勢(shì)識(shí)別的一開(kāi)始觸發(fā)一次
  // should-response-on-move 是在 move 過(guò)程中不斷觸發(fā)
  shouldScrollViewAccept() {
    'worklet'
    return true
  },

  // 這里返回 false,則 scroll-view 無(wú)法滾動(dòng)
  shouldScrollViewResponse(pointerEvent) {
    'worklet';
    return true;
  },

  // 手指滑動(dòng)離開(kāi)滾動(dòng)組件時(shí),指定衰減速度
  adjustDecelerationVelocity(velocity) {
    'worklet';
   return velocity;
  },

  // scroll-view 滾動(dòng)到邊界后,手指滑動(dòng),scroll 事件不再觸發(fā)
  handleScroll(evt) {
    'worklet';
  },

  // scroll-view 滾動(dòng)到邊界后,手指滑動(dòng),手勢(shì)回調(diào)仍然會(huì)觸發(fā)
  handleGesture(evt) {
    'worklet'
  },
});

# 示例四:手勢(shì)協(xié)商

一些場(chǎng)景下,我們會(huì)遇到手勢(shì)沖突。如下代碼所示,存在嵌套的 <vertical-drag-gesture-handler> 組件,我們希望 outer 手勢(shì)組件來(lái)處理縱向的拖動(dòng),inner 手勢(shì)組件處理列表的滾動(dòng),但實(shí)際僅 inner 的手勢(shì)回調(diào)會(huì)觸發(fā)。

嵌套的同類型手勢(shì)組件,當(dāng)內(nèi)層的手勢(shì)識(shí)別后,外層的手勢(shì)組件將不會(huì)被識(shí)別。

<vertical-drag-gesture-handler tag="outer">
  <vertical-drag-gesture-handler tag="inner" native-view="scroll-view">
    <scroll-view scroll-y></scroll-view>
  </vertical-drag-gesture-handler>
</vertical-drag-gesture-handler>

但上述場(chǎng)景又是很常見(jiàn)的,例如視頻號(hào)的評(píng)論列表,列表的滾動(dòng)和整個(gè)評(píng)論區(qū)的拖動(dòng)銜接的十分流暢。手勢(shì)協(xié)商機(jī)制用于解決該類問(wèn)題,使用上也十分簡(jiǎn)單,simultaneous-handlers 屬性聲明多個(gè)手勢(shì)可同時(shí)觸發(fā)。

<vertical-drag-gesture-handler tag="outer" simultaneous-handlers="{{["inner"]}}">
  <vertical-drag-gesture-handler tag="inner" simultaneous-handlers="{{["outer"]}}" native-view="scroll-view">
    <scroll-view scroll-y></scroll-view>
  </vertical-drag-gesture-handler>
</vertical-drag-gesture-handler>

此時(shí),outerinner 手勢(shì)組件的 on-gesture-event 回調(diào)會(huì)依次觸發(fā),結(jié)合上面提到的手勢(shì)控制原理,可以實(shí)現(xiàn)預(yù)期的效果。完整代碼參考示例 demo。