Este equipo de expertos pasados muchos días de investigación y de recopilar de datos, dieron con la respuesta, deseamos que todo este artículo sea de gran utilidad para tu plan.
Solución:
Basado en mi comentario en la respuesta de Nguyên Hoàng. Aquí hay otra forma de detener la animación en bucle si llama this.state.angle.stopAnimation()
:
runAnimation()
this.state.angle.setValue(0);
Animated.timing(this.state.angle,
toValue: 360,
duration: 8000,
easing: Easing.linear
).start((o) =>
if(o.finished)
this.runAnimation();
);
Puedes crear una variable stopAnimation
para detener la animación cuando quieras por solo cuando stopAnimation === false
luego devolver la llamada runAnimation
función. Como ejemplo:
this.state = stopAnimation: false
runAnimation()
this.state.spinValue.setValue(0);
Animated.timing(
this.state.spinValue,
toValue: 1,
duration: 3000,
easing: Easing.linear
).start( () =>
if(this.state.stopAnimation === false)
this.runAnimation();
);
Entonces solo necesita crear un botón que llame a la función this.state = stopAnimation: true
para detener la animación.
Ejemplo aquí: https://rnplay.org/apps/Lpmh8A.
Me gusta encapsular mis animaciones en ganchos, lo convierte en un patrón mucho más limpio, más fácil y más reutilizable que los componentes de clase. Así es como hago una animación en bucle con fácil control de inicio/parada en texto mecanografiado:
export const useBounceRotateAnimation = (running: boolean = true, rate: number = 300) =>
//Example of making an infinite looping animation and controlling it with a boolean
//Note that this assumes the "rate" is constant -- if you wanted to change the rate value after creation the implementation would have to change a bit
//Only create the animated value once
const val = useRef(new Animated.Value(0))
//Store a reference to the animation since we're starting-stopping an infinite loop instead of starting new animations and we aren't changing any animation values after creation. We only want to create the animation object once.
const anim = useRef(
Animated.loop(
Animated.timing(val.current,
toValue: 1,
duration: rate,
easing: Easing.linear,
useNativeDriver: true,
isInteraction: false,
)
)
).current
//Interpolate the value(s) to whatever is appropriate for your case
const interpolatedY = val.current.interpolate(
inputRange: [0, 0.5, 1],
outputRange: [0, 6, 0],
)
const interpolatedRotate = val.current.interpolate(
inputRange: [0, 0.25, 0.5, 1],
outputRange: ["0deg", "-3deg", "3deg", "0deg"],
)
//Start and stop the animation based on the value of the boolean prop
useEffect(() =>
if (running)
anim.start()
else
//When stopping reset the value to 0 so animated item doesn't stop in a random position
anim.stop()
val.current.setValue(0)
//Return a function from useEffect to stop the animation on unmount
return () => anim.stop()
//This useEffect should rerun if "running" or "anim" changes (but anim won't change since its a ref we never modify)
, [running, anim])
//Return the animated values. Use "as const" const assertion to narrow the output type to exactly the two values being returned.
return [interpolatedY, interpolatedRotate] as const
Utilizo esta implementación de gancho real para hacer que la imagen de un personaje “camine” en mi juego. Ahora en mi componente es muy fácil de usar:
const MyComponent = () =>
const [isRunning, setIsRunning] = useState(true)
const [translation, rotation] = useBounceRotateAnimation(isRunning)
return (
....rest of your component here, just setIsRunning(false) to stop animation whenever you need
)
Como puedes ver este patrón es muy limpio y reutilizable. El componente animado no necesita saber nada sobre la animación, solo consume los valores animados y le dice a la animación cuándo ejecutarse.
Al final de todo puedes encontrar los informes de otros gestores de proyectos, tú incluso puedes dejar el tuyo si te gusta.