wcandillon / react-native-redash

The React Native Reanimated and Gesture Handler Toolbelt
https://wcandillon.gitbook.io/redash/
MIT License
1.99k stars 117 forks source link

clamp stucked on edge for while and how to imperatively start spring() animation #97

Open sebqq opened 5 years ago

sebqq commented 5 years ago

Hello! I have two questions:

I've encountered one problem with using clamp() method in spring-based animation. Enclosing a gif:

2019-09-08 10 05 50

It seems like Animated object is always stucked while reaching min/max boundary which makes animation not so smooth. Is there anything I can do with it please? It seems like the more velocity i provide while gesture the longer stuck duration is.

Second question is more specific. I have this switch component which can be seen on gif preview above. Besides swipe gesture I would like to also achieve to start spring(?) animation whenever one of the options is pressed. I've found that there is nothing like snapTo callback within withSpring() function. Do I need to implement custom timing based animation next to spring animation?

In case it would be helpfull I'm enclosing my current spring animation setup:

const [state, translationX, velocityX] = useMemoOne(() => [
    new Value(State.UNDETERMINED),
    new Value(0),
    new Value(0)
  ]);

  const gestureEvent = onGestureEvent({
    state,
    translationX,
    velocityX
  });

  const translateX = useMemoOne(() => {
    return clamp(
      withSpring({
        value: translationX,
        velocity: velocityX,
        state,
        config: {
          damping: 7
        },
        snapPoints: snapPoints
      }),
      snapPoints[0],
      snapPoints[snapPoints.length - 1]
    );
  }, []);

For onPress behaviour I've implemented something like this:

const onOptionPressed = index => {
    setValue(index); // to keep option index for upper component purposes
    translationX.setValue(snapPoints[index]); // I tried to manually set transX
    state.setValue(State.BEGAN); // I tried to set State.BEGAN to simulate(?) pan gesture 
    // I know that setting state to began will not do much as state, same as velocity are 
    // provided by panGestureHandler and are dynamically change during gesture event
  };

Thank you so much!

wcandillon commented 5 years ago

Have you try diffClamp when the gesture is active and no clamp at all when the gesture is not active (so the spring will be natural).

state.setValue(State.BEGAN); I strongly recommend not updating these manually. Sometimes it can solves a particular problem but then it might cause issues later down the road. Try to create a new animation value that you can update so you don't need to update the state animation value.

wcandillon commented 5 years ago

I have the same problem when clamp work pretty well but has some issues. I will let you know as soon as I found a good solution for this problem.

sebqq commented 5 years ago

I was just trying to implement your suggestion without any success 😸bad for my that I have no experience with Java/Objective C.

It looks to me like clamp is waiting for animation to complete its "path" behind min/max boundaries to be able to get new values and during this time animted object is stucked at defined min/max.

Thanks for following up on this issue!

wcandillon commented 5 years ago

I noticed that setting the clamp on the translationY work pretty well: https://github.com/wcandillon/can-it-be-done-in-react-native/pull/63/files#diff-2a38087cb2be36de78068efd49fd3136R69

This has two tiny issues:

  1. It can snap to a position when releasing the gesture, even though we are already at this position
  2. It doesn't diffclamp when going outside the boundaries. If you try the real spotify app, you'll notice that they have the exact same "problem". It's not really a big issue I would say.
sebqq commented 5 years ago

Result within my Switch Component:

2019-09-11 09 22 25

const translateX = withSpring({
    value: clamp(
      translationX,
      snapPoints[0],
      snapPoints[snapPoints.length - 1]
    ),
    velocity: velocityX,
    state,
    config: {
      damping: 15,
      mass: 1,
      stiffness: 150,
      overshootClamping: false,
      restSpeedThreshold: 0.1,
      restDisplacementThreshold: 0.1
    },
    snapPoints: snapPoints
  });

Doesn't animation look exactly same as if there wasn't any clamp at all? I mean I've tried both,, without clamp and with clamp on withSpirng's value and it looks same to me 😺