Hi All. Today I will do a tutorial to make 1 swipe panel with panResponder.
Requirement
The problem poses for us the following requirements: The screen will include components:
- Swipe Panel: This Panel allows us to swipe, this Panel can swipe up and down
- Modal Panel: This Panel does not allow us to swipe, it will move under the Swipe Panel
- BackGround Panel: This is the Panel that will stand still and contain the controls, when the Swipe Panel goes up, all the controls in this Panel will be blocked and cannot be used.
- Opacity Panel: This panel only appears when the Swipe Panel goes up and disappears when the Swipe Panel returns to the correct starting position, it is responsible for blocking the entire BackGround Panel.
With Components as above, we have color it as follows
- Swipe Panel: blue
- Modal Panel: red
- BackGround Panel: yellow
About logic requirements are as follows:
- When the
Swipe Panel
leaves its original position and moves upwards, theOpacity Panel
will appear and block the entireBackGround Panel
, and theModal Panel
will move according to theSwipe Panel
Swipe Panel
is free to move up and down, but when the User releases his hand, theSwipe Panel
will have to automatically calculate the position so that:- The vertical position of
Swipe Panel
when swiping up is the height ofSwipe Panel
+Modal Panel
Swipe Panel
‘s standing position when swiping down is the starting point
- The vertical position of
You can see a sample gif, for example:
Ok we will start to do it, but to do this, you need to know about the following 2 knowledge:
Why Animated and Panresponse. Since Panresponse will help us calculate positions when User Swipe, Animated will help us to process effects more smoothly.
Setup
Panresponder
Here is the code that creates the Panresponder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <span class="token keyword">import</span> <span class="token punctuation">{</span> PanResponder <span class="token punctuation">,</span> Animated <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'react-native'</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> pan <span class="token operator">=</span> <span class="token function">useRef</span> <span class="token punctuation">(</span> <span class="token keyword">new</span> <span class="token class-name">Animated <span class="token punctuation">.</span> ValueXY</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> x <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">,</span> y <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> current <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">handleShouldSetPanResponder</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">evt <span class="token operator">:</span> any <span class="token punctuation">,</span> gestureState <span class="token operator">:</span> any</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> evt <span class="token punctuation">.</span> nativeEvent <span class="token punctuation">.</span> touches <span class="token punctuation">.</span> length <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">&&</span> Math <span class="token punctuation">.</span> <span class="token function">abs</span> <span class="token punctuation">(</span> gestureState <span class="token punctuation">.</span> dy <span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">5</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> panResponder <span class="token operator">=</span> PanResponder <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> onStartShouldSetPanResponder <span class="token operator">:</span> handleShouldSetPanResponder <span class="token punctuation">,</span> onMoveShouldSetPanResponder <span class="token operator">:</span> handleShouldSetPanResponder <span class="token punctuation">,</span> <span class="token function-variable function">onPanResponderMove</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token parameter">e <span class="token punctuation">,</span> gestureState</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Animated <span class="token punctuation">.</span> <span class="token function">event</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> dy <span class="token operator">:</span> pan <span class="token punctuation">.</span> y <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> useNativeDriver <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">(</span> e <span class="token punctuation">,</span> gestureState <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function-variable function">onPanResponderGrant</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> pan <span class="token punctuation">.</span> <span class="token function">setOffset</span> <span class="token punctuation">(</span> pan <span class="token punctuation">.</span> <span class="token function">__getValue</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> pan <span class="token punctuation">.</span> <span class="token function">setValue</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> x <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">,</span> y <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token function-variable function">onPanResponderRelease</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token parameter">_e <span class="token punctuation">,</span> gestureState</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> pan <span class="token punctuation">.</span> <span class="token function">flattenOffset</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> gestureState <span class="token punctuation">.</span> dy <span class="token operator">></span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">fadeOut</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token function">fadeIn</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token operator"><</span> Animated <span class="token punctuation">.</span> View ref <span class="token operator">=</span> <span class="token punctuation">{</span> ref <span class="token punctuation">}</span> <span class="token punctuation">{</span> <span class="token operator">...</span> panResponder <span class="token punctuation">.</span> panHandlers <span class="token punctuation">}</span> style <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span> pan <span class="token punctuation">.</span> <span class="token function">getLayout</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> styles <span class="token punctuation">.</span> swipePanel <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> <span class="token operator"><</span> Animated <span class="token punctuation">.</span> View style <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span> pan <span class="token punctuation">.</span> <span class="token function">getLayout</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> styles <span class="token punctuation">.</span> modalPanel <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token operator">/</span> <span class="token operator">></span> |
First of all we need to create a Panresponder
using the PanResponder.create
method and configure some options. And in our problem we need to configure what
Check Should Panresponder run?
The actual problem will have a lot of cases and in that there are a few cases like this we need to block the Panresponder:
- User touch and do not swipe
- User swipe but swipe distance is too short
To solve this problem, Panresponder
has Panresponder
by allowing us to configure options and here I use 2 options:
onStartShouldSetPanResponder
onMoveShouldSetPanResponder
Like the following code:
1 2 3 4 5 6 7 8 9 | <span class="token keyword">const</span> <span class="token function-variable function">handleShouldSetPanResponder</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">evt <span class="token operator">:</span> any <span class="token punctuation">,</span> gestureState <span class="token operator">:</span> any</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> evt <span class="token punctuation">.</span> nativeEvent <span class="token punctuation">.</span> touches <span class="token punctuation">.</span> length <span class="token operator">===</span> <span class="token number">1</span> <span class="token operator">&&</span> Math <span class="token punctuation">.</span> <span class="token function">abs</span> <span class="token punctuation">(</span> gestureState <span class="token punctuation">.</span> dy <span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">5</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> panResponder <span class="token operator">=</span> PanResponder <span class="token punctuation">.</span> <span class="token function">create</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> onStartShouldSetPanResponder <span class="token operator">:</span> handleShouldSetPanResponder <span class="token punctuation">,</span> onMoveShouldSetPanResponder <span class="token operator">:</span> handleShouldSetPanResponder <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
These 2 options will use handleShouldSetPanResponder
to check how many times the User toucher and how far the User has handleShouldSetPanResponder
, the handleShouldSetPanResponder
function will return true
or false
results ( true
then Panresponder
will run and false
will not)
onPanResponderMove
This is the most important part, in this function we will decide the movement of the panels by setting the corresponding coordinates.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <span class="token function-variable function">onPanResponderMove</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token parameter">e <span class="token punctuation">,</span> gestureState</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> Animated <span class="token punctuation">.</span> <span class="token function">event</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token keyword">null</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> dy <span class="token operator">:</span> pan <span class="token punctuation">.</span> y <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> useNativeDriver <span class="token operator">:</span> <span class="token boolean">false</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">)</span> <span class="token punctuation">(</span> e <span class="token punctuation">,</span> gestureState <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> |
Here I am returning onPanResponderMove
be an Animated.event
, what this means. PanResponder
will create a function that will automatically take 2 gestureState
values dx
and dy
, then it will update the corresponding Animated x
and y
values. And of course when the value of the Animated is updated, the remaining task of the Animated.View
will perform the change of the value.
onPanResponderGrant
Each time the User swipe, this function will be called only once with the purpose of setting the necessary values (depending on what we need for purposes).
1 2 3 4 5 | <span class="token function-variable function">onPanResponderGrant</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> pan <span class="token punctuation">.</span> <span class="token function">setOffset</span> <span class="token punctuation">(</span> pan <span class="token punctuation">.</span> <span class="token function">__getValue</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> pan <span class="token punctuation">.</span> <span class="token function">setValue</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> x <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">,</span> y <span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> |
In this code we will be interested in a value that is Offset
Offset
translated into Vietnamese isGiá Trị Bù
.- I’ll explain why we need this
Giá Trị Bù
:- When you touch anywhere on the phone screen and swipe, we cannot calculate exactly where coordinates are.
- Also in the function
onPanResponderMove
will only return you the distance that you have swipe
Based on the above two problems, Offset
, also known as Offset
Giá Trị Bù
, was born to solve the problem.
For example:
- You are at position
{ x: 0, y: 0 }
- You swipe up the first time and the distance is 200
- You stop swipe
- You swipe up a second time and the distance is 200
With this problem, in the second time we want that the starting point must be at { x: 0, y: 200 }
right?
And the purpose of onPanResponderGrant
is to solve the problem above, we set the Offset
the current position (before swipe), and then based on this value we can calculate the exact coordinates. starting and moving coordinates.
And the Value
after storing by setting Offset
, we will proceed to reset it to { x: 0, y: 0 }
onPanResponderRelease
1 2 3 4 | <span class="token function-variable function">onPanResponderRelease</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token parameter">_e <span class="token punctuation">,</span> gestureState</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> pan <span class="token punctuation">.</span> <span class="token function">flattenOffset</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
onPanResponderRelease
: this is the function that will run when the User finishes the swipe (User lifts his hand off the screen), and here we will call the function pan.flattenOffset();
.
pan.flattenOffset();
: It will reset the value of Animated by merging the current value with the Offset
value
Example In onPanResponderRelease
Animated value Offset
is { x: 0, y: 200 }
and value Value
of Animated is { x: 0, y: 200 }
, after the call pan.flattenOffset();
the Offset
value is { x: 0, y: 0 }
and the value
of the Animated is { x: 0, y: 400 }
.
So in this function onPanResponderRelease
is the end of a swipe process, this function combined with onPanResponderGrant
will ensure that we will always have the last value of the swipe.
Part 1 Conlusion
Part 1 we will stop at understanding the principle of operation of the PanResponder
, in the next part we will go into more detail about the specific problem that we mentioned above. Goodbye and see you again mn.
If you want to see the code, please see here