javascript - Reanimated v2 - Valori partajate sincronizate


Întrebare

Încerc să creez această animație folosind Reanimated v2:

Aceasta este implementarea actuală:

const opacity1 = useSharedValue(0);
const opacity2 = useSharedValue(0);
const opacity3 = useSharedValue(0);
useEffect(() => {
  const duration = 600;
  const timingOptions = { duration: duration };
  const pulse = withTiming(1, timingOptions);
  const repeated = withRepeat(pulse, -1, true);
  opacity1.value = repeated;
  // *
  opacity2.value = withDelay(duration / 2, repeated);
  // *
  opacity3.value = withDelay(duration, repeated);
}, []);

Problema este că acolo unde am marcat codul cu // * par să existe unele întârzieri aleatorii (probabil din cauza execuției JS) care fac ca cele trei puncte să ajungă uneori să fie sincronizate (având aceeași opacitate).

Presupun că problema este că actualizarea acelor 3 valori nu este atomică, așa că orice poate să se întâmple între acele atribuiri.

Care este cel mai bun mod de a rezolva acest lucru și de a avea acele 3 valori partajate cu o întârziere deterministă între ele?

Ce am încercat?

  • Am încercat să folosesc 1 useSharedValue și 2 useDerivedValue dar matematica pentru a face ca unul să înceapă de la 0, altul să înceapă de la 0,5 și altul să înceapă de la 1 nu este trivială (simpla adunare a 0,5 între ele și aplicarea modulo (%) la 1 nu ține cont de withRepeat care revine după ce ajunge la 1)
  • Am încercat să folosesc un useSharedValue([0, 0, 0]) și apoi să îl actualizez cu o operațiune atomică, dar se pare că nu este suportat

Răspuns #1

Am găsit o soluție, nu sunt sigur dacă este cea mai bună, dar deocamdată funcționează.

Ideea este:

  • ai o valoare partajată „progres” a cărei mapare 0 -> 1 corespunde unui ciclu complet de animație (de ex. 0 -> 1 -> 0)
  • au 3 valori derivate care încep în momente diferite și se interpolează diferit:

    • unu 0 -> 0,5 -> 1 -> 0,5 -> 0
    • unu 0,5 -> 1 -> 0,5 -> 0 -> 0,5
    • unu 1 -> 0,5 -> 0 -> 0,5 -> 1

și iată codul:

const progress = useSharedValue(0);
useEffect(() => {
  const pulse = withTiming(1, { duration: 1200, easing: Easing.linear });
  progress.value = withRepeat(pulse, -1, false);
}, []);

const opacity1 = useDerivedValue(() =>
  interpolate(progress.value, [0, 0.25, 0.5, 0.75, 1], [0, 0.5, 1, 0.5, 0])
);
const opacity2 = useDerivedValue(() =>
  interpolate(progress.value, [0, 0.25, 0.5, 0.75, 1], [0.5, 1, 0.5, 0, 0.5])
);
const opacity3 = useDerivedValue(() =>
  interpolate(progress.value, [0, 0.25, 0.5, 0.75, 1], [1, 0.5, 0, 0.5, 1])
);