diff --git a/cpp/RNSkSkottieView.h b/cpp/RNSkSkottieView.h index bb48b9e..2baf9e8 100644 --- a/cpp/RNSkSkottieView.h +++ b/cpp/RNSkSkottieView.h @@ -28,6 +28,8 @@ #include "SkCanvas.h" #include "SkPictureRecorder.h" #include +#include +#include #pragma clang diagnostic pop @@ -81,7 +83,7 @@ class RNSkSkottieRenderer : public RNSkRenderer, public std::enable_shared_from_ } bool isPaused() { - return _lastPauseTime > 0.0; + return _lastPauseTime > 0.0 || _startTime == -1.0; } void pause() { @@ -181,39 +183,45 @@ class RNSkSkottieView : public RNSkView { RNSkView::setJsiProperties(props); - for (auto& prop : props) { + // We need to make sure .start gets called last. + // It might happen that setJsiProperties gets called multiple times before the view is actually ready. + // In this case all our "props" will be stored, and then once its ready setJsiProperties gets called + // with all the props at once. Then .start has to be called last, otherwise the animation will not play. + std::vector> sortedProps(props.begin(), props.end()); + if (sortedProps.size() > 1) { + // Custom sort function to place 'start' at the end + std::sort(sortedProps.begin(), sortedProps.end(), + [](const auto& a, const auto& b) { + return !(a.first == "start") && (b.first == "start" || a.first < b.first); + }); + } + + for (auto& prop : sortedProps) { if (prop.first == "src" && prop.second.getType() == RNJsi::JsiWrapperValueType::HostObject) { std::static_pointer_cast(getRenderer())->setSrc(prop.second.getAsHostObject()); renderImmediate(); // Draw the first frame - } - if (prop.first == "scaleType") { + } else if (prop.first == "scaleType") { std::static_pointer_cast(getRenderer())->setResizeMode(prop.second.getAsString()); - } - } - } + } else if (prop.first == "setProgress") { + // Get first argument as number as it contains the updated value + auto progressValue = prop.second.getAsNumber(); + std::static_pointer_cast(getRenderer())->setProgress(progressValue); + requestRedraw(); + } else if (prop.first == "start") { + std::static_pointer_cast(getRenderer())->setStartTime(RNSkTime::GetSecs()); + setDrawingMode(RNSkDrawingMode::Continuous); + } else if (prop.first == "pause") { + if (std::static_pointer_cast(getRenderer())->isPaused()) { + continue; + } - jsi::Value callJsiMethod(jsi::Runtime& runtime, const std::string& name, const jsi::Value* arguments, size_t count) override { - if (name == "setProgress") { - // Get first argument as number as it contains the updated value - auto progressValue = arguments[0].asNumber(); - std::static_pointer_cast(getRenderer())->setProgress(progressValue); - requestRedraw(); - } else if (name == "start") { - std::static_pointer_cast(getRenderer())->setStartTime(RNSkTime::GetSecs()); - setDrawingMode(RNSkDrawingMode::Continuous); - } else if (name == "pause") { - if (std::static_pointer_cast(getRenderer())->isPaused()) { - return {}; + setDrawingMode(RNSkDrawingMode::Default); + std::static_pointer_cast(getRenderer())->pause(); + } else if (prop.first == "reset") { + std::static_pointer_cast(getRenderer())->resetPlayback(); + setDrawingMode(RNSkDrawingMode::Default); // This will also trigger a requestRedraw } - - setDrawingMode(RNSkDrawingMode::Default); - std::static_pointer_cast(getRenderer())->pause(); - } else if (name == "reset") { - std::static_pointer_cast(getRenderer())->resetPlayback(); - setDrawingMode(RNSkDrawingMode::Default); // This will also trigger a requestRedraw } - - return {}; } }; } // namespace RNSkia diff --git a/example/src/App.tsx b/example/src/App.tsx index f910514..391e51e 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -6,6 +6,7 @@ import { StyleSheet, SafeAreaView, ScrollView, + Switch, } from 'react-native'; import { SkiaSkottieView, @@ -15,6 +16,7 @@ import { import * as Animations from './animations'; import LottieView from 'lottie-react-native'; import DotLottieAnimation from './animations/Hands.lottie'; +import { useMemo } from 'react'; const animations = { ...Animations, @@ -79,6 +81,61 @@ function SkottieImperativeAPI({ source }: { source: AnimationObject }) { ); } +function SkottiePropsAPI({ source }: { source: AnimationObject }) { + const [loop, setLoop] = React.useState(true); + const [autoPlay, setAutoPlay] = React.useState(false); + const [speed, setSpeed] = React.useState(1); + const [_progress, setProgress] = React.useState(0); + + return ( + +