2

Every document of react reanimated is using class components i've tried to change the way of doing a simple opacity animation of a button but i can't for the life of me make it work, it seems set is not working, if i change set to Opacity.setvalue(0) it works but i need set to in order to use clock for other animations, any help please.

import React, { useState } from "react";
import { View, Text, StyleSheet, Image, Dimensions } from "react-native";
import Animated, { Easing } from "react-native-reanimated";
import { TapGestureHandler, State } from "react-native-gesture-handler";

function MusicApp() {
  const {
    Value,
    Clock,
    startClock,
    stopClock,
    debug,
    timing,
    clockRunning,
    block,
    cond,
    set,
    eq
  } = Animated;


  const { width, height } = Dimensions.get("window");
  const [buttonOpacity, setbuttonOpacity] = useState(1);

 const Opacity = new Value(1);   



  function onStateChange() {
    Animated.event([
      {
        nativeEvent: ({state}) =>
          Animated.block([cond(eq(state, State.END),set(Opacity,0) )
          ])
      }
    ]);
  }

  return (
    <View style={{ backgroundColor: "black", justifyContent: "flex-end" }}>
      <View
        style={{ position: "absolute", top: 0, bottom: 0, left: 0, right: 0 }}
      >
        <Image
          source={require("../assets/bg.jpg")}
          style={{ height: height, width: width }}
        />
      </View>

      <View style={{ height: height / 3, justifyContent: "center" }}>
        <TapGestureHandler
          onHandlerStateChange={() => {
            onStateChange();
          }}
        >
          <Animated.View style={{ ...styles.button, opacity: Opacity}}>
            <Text style={{ fontSize: 20 }}>SIGN IN</Text>
          </Animated.View>
        </TapGestureHandler>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center"
  },
  button: {
    backgroundColor: "red",
    height: 70,
    marginHorizontal: 20,
    borderRadius: 35,
    alignItems: "center",
    justifyContent: "center"
  },
  button2: {
    backgroundColor: "blue",
    height: 70,
    marginHorizontal: 20,
    borderRadius: 35,
    alignItems: "center",
    justifyContent: "center"
  }
});

export default MusicApp;

2 Answers2

2

Reanimated uses declarative api rather than imperative api in default Animated api i.e .start() .setValue().

Clock() is special node in reanimated , which is under ther hood just a value which updated timestamp per every frame.

using this clock, you can define helper functions like

function runTiming(clock, value, dest) {
  const state = {
    finished: new Value(0),
    position: new Value(0),
    time: new Value(0),
    frameTime: new Value(0),
  };

  const config = {
    duration: 5000,
    toValue: new Value(0),
    easing: Easing.inOut(Easing.ease),
  };

  return block([
    cond(
      clockRunning(clock),
      [
        // if the clock is already running we update the toValue, in case a new dest has been passed in
        set(config.toValue, dest),
      ],
      [
        // if the clock isn't running we reset all the animation params and start the clock
        set(state.finished, 0),
        set(state.time, 0),
        set(state.position, value),
        set(state.frameTime, 0),
        set(config.toValue, dest),
        startClock(clock),
      ]
    ),
    // we run the step here that is going to update position
    timing(clock, state, config),
    // if the animation is over we stop the clock
    cond(state.finished, debug('stop clock', stopClock(clock))),
    // we made the block return the updated position
    state.position,
  ]);
}

and in component, there are multiple ways to animate a value.

i recommed using Code or useCode from reanimated

you can use it like

function OpacityButton({}) {
  const opacity = new Value(1);
  const clock = new Clock();
  const clicked = new Value(0);
  const buttonState = new Value();

  useCode(() => block([cond(eq(clicked, 1), set(opacity, runTiming(clock, opacity, 0.5)))]));

  return (
    <TouchableOpacity onPress={() => clicked.setValue(1)}>
      <Animated.View style={[styles.button, { opacity }]} />
    </TouchableOpacity>
  );
}

this is just 70% of code. But you may extend it to your requirement.

GollyJer
  • 23,857
  • 16
  • 106
  • 174
vamshi krishna
  • 2,618
  • 1
  • 11
  • 18
  • Hey thanks for the help, im still a noob for react native stuff, how should i use the buttonState that you provided, also what should i deconstruct in the OpacityButton fuction and where should i call it. – Choza de thunder Mar 07 '20 at 23:45
  • Clearest answer so far, just another question, how differently would you do it for an array of animated value? – iWillGetBetter Jul 21 '20 at 04:56
1

You can map the tap state of the button to a tap variable. Then you can use the useCode hook with tap as a dependency and change the opacity from 1 to 0 accordingly.

const { height } = Dimensions.get('window');
const { eq, useCode, timing, Clock, Value, set, cond } = Animated;

const App = () => {
  const [tap, setTap] = useState(new Value(-1));
  const opacity = new Value(1);
  const handleChange = (e) => {
    tap.setValue(e.nativeEvent.state);
  };

  useCode(() => cond(eq(tap, State.BEGAN), set(opacity, 0), 0), [tap]);
  return (
    <>
      <View
        style={{
          height: height / 3,
          justifyContent: 'flex-end',
          backgroundColor: 'green',
        }}
      >
        <TapGestureHandler onHandlerStateChange={handleChange}>
          <Animated.View style={{ ...styles.button, opacity }}>
            <Text style={{ fontSize: 20 }}>SIGN IN</Text>
          </Animated.View>
        </TapGestureHandler>
      </View>
    </>
  );
};
GollyJer
  • 23,857
  • 16
  • 106
  • 174
Abhishek Prashant
  • 365
  • 1
  • 4
  • 14
  • this doesn't animate value. its just sets it it 0 when tapped. almost equal to ```A.View style={{opacity: cond(eq(tapState, State.BEGAN), 0,1)}} />``` – vamshi krishna Mar 07 '20 at 07:52