# Gesture system
In business development, we often need to listen to nodes touch Event that handles drag and drop and zoom related logic. Because Skyline Using a two-thread architecture, in such interactive animation, there will be a large asynchronous delay, which can be referred to wxs Responding to Events。
Skyline in wxs The code runs on the JS Thread, while events are generated in the UI Thread. Therefore, wxs animation Performance has been reduced, in order to improve the effect of the interactive experience of the Mini Program, we have built a number of gesture components. The advantages of using gesture components include
- Avoid listening to developers
touchEvents, calculate the complex steps of gesture logic on your own - The gesture component directly in the
UIThread response, avoiding the need to pass to theJSDelays caused by threads
# Effect display
The following figure demonstrates the use of gestures, negotiation gestures to achieve the drag ball, half-screen pop-up gesture drag off, segmented half-screen and other effects.Click to see more Skyline Example。

Scan code Mini Program examples, respectively, to experience Basic gesture and Negotiation gesture New features

# Gesture component
| Component name | Trigger timing |
|---|---|
<tap-gesture-handler> | Triggered when clicked |
<double-tap-gesture-handler> | Triggered when double-click |
<scale-gesture-handler> | Triggered when multi-finger scaling |
<force-press-gesture-handler> | iPhone Equipment re-triggered on time |
<pan-gesture-handler > | Drag (Horizontal/Longitudinal) when triggered |
<vertical-drag-gesture-handler> | Triggered when longitudinal sliding |
<horizontal-drag-gesture-handler > | Triggered when lateral sliding |
<long-press-gesture-handler> | Long time trigger |
# Working principle
Gesture component is virtual component, the real response to the event is its direct child node. In the code below, we give container The node adds two types of gesture listening.
- When swiping horizontally across the screen,
horizontal dragThe callback of the gesture node will be triggered - When swiping lengthwise on the screen,
vertical-dragThe callback of the gesture node will be triggered.
<horizontal-drag-gesture-handler >
<vertical-drag-gesture-handler>
<view id="container"></view>
</vertical-drag-gesture-handler>
</horizontal-drag-gesture-handler >
When you touch the screen, the rendering engine recognizes gestures from the inside out, and when one of the listeners meets the criteria, the rest of the listeners fail. As in scroll-view When you add a longitudinal gesture monitor internally, it will block scroll-view Inside the gesture listener, resulting in an inability to swipe.
<scrol-view>
<vertical-drag-gesture-handler>
<view id="container"></view>
</vertical-drag-gesture-handler>
</scroll-view>
It's important to note,pan The ratio of determining conditions for type vertical-drag To be loose, so when sliding lengthwise,vertical-drag Will respond, and pan Will fail. When sliding horizontally,pan Type will respond.
<vertical-drag-gesture-handler>
<pan-gesture-handler >
<view id="container"></view>
</pan-gesture-handler >
</vertical-drag-gesture-handler>
# Common attributes
| attribute | type | Default value | Required | Introductions |
|---|---|---|---|---|
| tag | string | nothing | no | Component identity when declaring gesture negotiation |
| worklet:ongesture | eventhandler | nothing | no | Gesture Processing Callback |
| worklet:should-response-on-move | callback | nothing | no | Whether the gesture responds during finger movement |
| worklet:should-accept-gesture | callback | nothing | no | Whether gestures should be recognized |
| simultaneous-handlers | Array<string> | [] | no | Declare gesture nodes that can be triggered simultaneously |
| native-view | string | nothing | no | Native node type for proxy |
native-view The supported enumeration values are scroll-view and swiperWhen scrolling the container lengthwise, use the <vertical-drag-gesture-handler> The gesture component represents the internal gesture, and when scrolling horizontally, the <horizontal-drag-gesture-handler >。
eventhandlerThe type is an event callback, with no return valuecallbackA type is a callback function that the developer registers with the component and is executed at the appropriate time to read the return value.- All callbacks can only pass in one worklet Callback
# Event callback parameter
# worklet:should-response-on-move
Parameters returned pointerEvent The fields are as follows. Callback each time the touch moves, returning the false The corresponding gesture component cannot receive the move Events.
| attribute | type | Introductions |
|---|---|---|
| identifier | number | Touch Object's unique identifier |
| type | string | Type of event |
| deltaX | number | Last time, x Axis moving coordinates |
| deltaY | number | Last time, Y Axis moving coordinates |
| clientX | number | Contact with respect to the left edge of the visible visual X coordinate |
| clientY | number | Contact with respect to the upper edge of the visible visual Y coordinate |
| radiusX | number | Returns the horizontal axis of the smallest ellipse capable of surrounding the contact area (X axis) radius |
| radiusY | number | Returns the vertical axis of the smallest ellipse capable of surrounding the contact area (Y axis) radius |
| RotationAngle | number | Returns an angle value representing the value described above by radiusX and radiusY The ellipse described needs to be rotated clockwise in order to cover the contact area between the user and the plane as accurately as possible |
| force | number | The user's pressure on the touch plane |
| timeStamp | number | The time stamp triggered by the event |
Page({
shouldResponseOnMove(pointerEvent) {
'worklet'
return false
}
})
# worklet:should-accept-gesture
The usage is as follows. Frame gesture recognition takes effect when it calls back, and it is up to the developer to decide whether the gesture takes effect. with Pan Hand gestures, for example.
Enter when you touch screen State.Possible Status,shouldAcceptGesture return false After entering State.CANCELLED Status, Return true After entering State.Begin Status, can continue to receive formalities move Events.
Page({
shouldAcceptGesture() {
'worklet'
return false
}
})
# worklet:ongesture
The parameters returned by different types of gesture components are as follows
# tap / double-tap
| attribute | type | Introductions |
|---|---|---|
| state | number | Gesture state |
| absoluteX | number | Relative to the global X coordinate |
| absoluteY | number | Relative to the global Y coordinate |
# pan / vertical-drag / horizontal drag
| attribute | type | Introductions |
|---|---|---|
| state | number | Gesture state |
| absoluteX | number | Relative to the global X coordinate |
| absoluteY | number | Relative to the global Y coordinate |
| deltaX | number | Last time, x Axis moving coordinates |
| deltaY | number | Last time, Y Axis moving coordinates |
| velocityX | number | The lateral speed of the finger as it leaves the screen (pixel per second) |
| velocityY | number | The vertical speed of the finger as it leaves the screen (pixel per second) |
# scale
| attribute | type | Introductions |
|---|---|---|
| state | number | Gesture state |
| focalX | number | Center point with respect to the global X coordinate |
| focalY | number | Center point with respect to the global Y coordinate |
| focalDeltaX | number | Relative to the last time, the center point in the X Axis moving coordinates |
| focalDeltaY | number | Relative to the last time, the center point in the Y Axis moving coordinates |
| scale | number | Magnified or reduced ratio |
| horizontalScale | number | scale The transverse component of |
| verticalScale | number | scale The longitudinal component of the |
| rotation | number | Angle of swing (in radians) |
| velocityX | number | The lateral speed of the finger as it leaves the screen (pixel per second) |
| velocityY | number | The vertical speed of the finger as it leaves the screen (pixel per second) |
| pointerCount | number | Number of fingers tracked |
- When multiple fingers slide,
focalXandfocalYCoordinates for a central focus of a plurality of touch points - When one finger slides,
pointerCount = 1, the same effect at this timepan-gesture-handler,scaleThe gesture ispanOf the superset.
# long-press
| attribute | type | Introductions |
|---|---|---|
| state | number | Gesture state |
| absoluteX | number | Relative to the global X coordinate |
| absoluteY | number | Relative to the global Y coordinate |
| translationX | number | Relative to the initial touch point of the X Axis offset |
| translationY | number | Relative to the initial touch point of the Y Axis offset |
| velocityX | number | The lateral speed of the finger as it leaves the screen (pixel per second) |
| velocityY | number | The vertical speed of the finger as it leaves the screen (pixel per second) |
# force-press
| attribute | type | Introductions |
|---|---|---|
| state | number | Gesture state |
| absoluteX | number | Relative to the global X coordinate |
| absoluteY | number | Relative to the global Y coordinate |
| pressure | number | Pressure size |
# Gesture state
All gestures worklet:ongesture The callback will always return a state Status field.
enum State {
// Gesture not recognized
POSSIBLE = 0,
// Gesture recognized
BEGIN = 1,
// Continuous gesture active state
ACTIVE = 2,
// Gesture termination
END = 3,
// Gesture cancellation
CANCELLED = 4,
}
We divide gestures into two types:
- Discrete Gestures:
tapanddouble-tap, Triggered Only Once - Continuous gestures: Other types of gesture components, finger dragging triggers multiple times
tap-gesture-handler Returned by the gesture component state Always for 1。
pan-gesture-handler The gesture component during a complete drag,state Will change in the following manner
- When your finger touches the screen,
state = 0 - Moving a short distance,
panWhen the gesture determination is in effect,state = 1 - Keep moving,
state = 2 - Finger off the screen
state = 3
Because nested gestures conflict (only one final decision is recognized), successive gestures state The changes may have the following scenarios, the developer needs according to the state Value to handle some exceptional cases.
POSSIBLE -> BEGIN -> ACTIVE -> ENDNormal flowPOSSIBLE -> BEGIN -> ACTIVE -> CANCELLEDAdvance interruptionPOSSIBLE -> CANCELLEDGesture not recognized
Not all continuous gestures have POSSIBLE Status, such as scale-gesture-handler Gesture component, when the two fingers touch and let go,state The changes are as follows:
- Two-fingered touch screen,
state = 1, pointerCount = 2 - Double finger magnification operation,
state = 2, pointerCount = 2 - Two fingers off the screen,
state = 3, pointerCount = 1♪ and then we'll call it back a.state = 1, pointerCount = 1b.state = 2, pointerCount = 1c.state = 3, pointerCount = 0
# Note
- The gesture component is available only in
SkylineCan be used in rendering mode - The gesture component is a virtual component and will not be laid out.
style、classIs invalid. - A gesture component can contain only one direct child node, otherwise it is not valid
- The parent component style of a gesture component directly affects its children
- The callback function of the gesture component must be declared as
workletfunction - Gestures are different from ordinary
touchEvent, will not proceed to bubble - Of the gesture component.
eventhandler / callbackMust be declared asworkletFunction, the callback in theUIThread Trigger
# Methods of Use
# sample code
Preview the effect in developer tools
# Chaining API init Function sample code
Preview the effect in developer tools
# Example 1: Listen for drag gestures
<pan-gesture-handler on-gesture-event="handlePan">
<view></view>
</pan-gesture-handler >
Page({
handlePan (possibly ) {
"worklet"
console.log(evt.translateX)
},
})
# Example 2: Listening for nested gestures
<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 >
# Example 3: Proxy native component internal gestures
for <scroll-view> and <swiper> Such a scrolling container internally handles scrolling operations based on gestures. Compared to web,skyline Provides a lower level access mechanism, so that in some complex interactions, you can do more granular, phased control.
<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>
Rolling lengthwise <scroll-view> For example, you can use <vertical-drag-gesture-handler> Gesture components, and declare that native-view="scroll-view" To represent their internal gestures.
# Rolling events
When the list is scrolled, the event callback of the gesture component and the <scroll-view> of scroll Event callbacks are triggered, and they differ in that:
scrollEvents are triggered only when rolling, when the top/After the bottom, no more callbackson-gesture-eventGesture callbacks trigger when the finger is swiped across the screen until the hand is released
# Gesture control
In the previous introduction to continuous gesture states, we know that gestures have their own recognition process. for example vertical-drag Gesture, when the finger touches for POSSIBLE State, moves a short distance before being recognized as BEGIN State, at which time the gesture is said to be recognized (theACCEPT)。
# 1. Gesture recognition
should-accept-gesture Property allows the developer to register a callback, and returns a boolean value that participates in theGesture recognitionOf the process. When returning false When the touch gesture is no longer in effect, the associated <scroll-view> Components cannot be scrolled either.
# 2. Event distribution
should-response-on-move Property allows the developer to register a callback, and returns a boolean value that participates in theEvent distributionOf the process. When returning false When, when move Of the events are no longer distributed, the associated <scroll-view> No, keep rolling. This callback will continue to trigger as the finger moves and can be changed at any time to control the scroll container to continue/Pause scrolling.
Page({
// Here to return False, then scroll-view Unable to scroll
// should-accept-gesture Will trigger once at the beginning of gesture recognition.
// should-response-on-move Was in the move Constantly triggered in the process
shouldScrollViewAccept() {
'worklet'
return true
},
// Here to return False, then scroll-view Unable to scroll
shouldScrollViewResponse(pointerEvent) {
'worklet'
return true
},
// Specifies the decay rate when the finger slides away from the rolling assembly
adjustDecelerationVelocity(velocity) {
'worklet'
return velocity
},
// scroll-view After scrolling to the border, slide your finger, scroll Events are no longer triggered
handleScroll (possibly ) {
'worklet'
},
// scroll-view After scrolling to the border, the finger slides and the gesture callback still triggers
handleGesture (possibly ) {
'worklet'
},
})
# Example 4: Gesture Negotiation
In some cases, we will encounterGesture conflictAs the code below shows, there are nested <vertical-drag-gesture-handler> Components. We hope that Outer The gesture component to handle the longitudinal drag,Inner The gesture component handles the scrolling of the list, but actually only Inner The gesture callback is triggered.
Nested gesture components of the same type, when the inner gesture recognition, the outer gesture components will not be recognized.
<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>
But the above scenario is very common, such as WeChat Channels comment list, the list of scrolling and the entire comment section of the link is very smooth. Gesture negotiation mechanism is used to solve this problem, and it is also very simple to use.simultaneous-handlers Property declares that multiple gestures can be triggered at the same time.
<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>
At this time,Outer and Inner Of the gesture component. on-gesture-event Callbacks will be triggered in turn, in combination with the aboveGesture controlPrinciple, can achieve the desired effect. Full Code ReferenceExample Demo。