diff --git a/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt b/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt index 49e09cf..071ca2f 100644 --- a/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt +++ b/android/src/main/java/com/rivereactnative/RiveReactNativeView.kt @@ -16,13 +16,15 @@ import com.facebook.react.uimanager.ThemedReactContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.lang.IllegalStateException import java.net.URL class RiveReactNativeView(private val context: ThemedReactContext) : FrameLayout(context), LifecycleEventListener { private var riveAnimationView: RiveAnimationView private var resId: Int = -1 + private var url: String? = null private val httpClient = ViewModelProvider(context.currentActivity as ViewModelStoreOwner).get(HttpClient::class.java) - private var autoPlayChanged = true + private var shouldBeReloaded = true enum class Events(private val mName: String) { PLAY("onPlay"), @@ -135,49 +137,70 @@ class RiveReactNativeView(private val context: ThemedReactContext) : FrameLayout } fun stop() { - riveAnimationView.setRiveResource(resId, autoplay = false) + shouldBeReloaded = true + reloadIfNeeded() } fun update() { - if (autoPlayChanged) { - if (riveAnimationView.autoplay) { - riveAnimationView.play() - } else { - riveAnimationView.stop() - } - } - autoPlayChanged = false + reloadIfNeeded() } - fun setResourceName(resourceName: String) { - resId = resources.getIdentifier(resourceName, "raw", context.packageName) - riveAnimationView.setRiveResource(resId, autoplay = false) // prevent autoplay + fun setResourceName(resourceName: String?) { + resourceName?.let { + resId = resources.getIdentifier(resourceName, "raw", context.packageName) + } ?: run { + resId = -1 + } + + shouldBeReloaded = true } fun setFit(rnFit: RNFit) { val riveFit = RNFit.mapToRiveFit(rnFit) riveAnimationView.fit = riveFit + riveAnimationView.drawable.invalidateSelf() // TODO: probably it should be a responsibility of rive-android itself } fun setAlignment(rnAlignment: RNAlignment) { val riveAlignment = RNAlignment.mapToRiveAlignment(rnAlignment) riveAnimationView.alignment = riveAlignment + riveAnimationView.drawable.invalidateSelf() // TODO: probably it should be a responsibility of rive-android itself } fun setAutoplay(autoplay: Boolean) { - if (riveAnimationView.autoplay != autoplay) { - autoPlayChanged = true - } riveAnimationView.autoplay = autoplay + shouldBeReloaded = true + } + + fun setUrl(url: String?) { + this.url = url + shouldBeReloaded = true + } + + private fun reloadIfNeeded() { + if (shouldBeReloaded) { + url?.let { + if (resId == -1) { + setUrlRiveResource(it) + } + } ?: run { + if (resId != -1) { + riveAnimationView.setRiveResource(resId, fit = riveAnimationView.fit, alignment = riveAnimationView.alignment, autoplay = riveAnimationView.autoplay) + url = null + } else { + throw IllegalStateException("You must provide a url or a resourceName!") + } + } + shouldBeReloaded = false + } } - fun setUrl(url: String) { + private fun setUrlRiveResource(url: String) { httpClient.byteLiveData.observe(context.currentActivity as LifecycleOwner, // needs a fix Observer { bytes -> // Pass the Rive file bytes to the animation view riveAnimationView.setRiveBytes( bytes, - // Fit the animation to the cover the entire view fit = riveAnimationView.fit, alignment = riveAnimationView.alignment, autoplay = riveAnimationView.autoplay @@ -188,15 +211,17 @@ class RiveReactNativeView(private val context: ThemedReactContext) : FrameLayout } fun setArtboardName(artboardName: String) { - riveAnimationView.artboardName = artboardName + riveAnimationView.artboardName = artboardName // it causes reloading } fun setAnimationName(animationName: String) { riveAnimationView.drawable.animationName = animationName + shouldBeReloaded = true } fun setStateMachineName(stateMachineName: String) { riveAnimationView.drawable.stateMachineName = stateMachineName + shouldBeReloaded = true } diff --git a/android/src/main/java/com/rivereactnative/RiveReactNativeViewManager.kt b/android/src/main/java/com/rivereactnative/RiveReactNativeViewManager.kt index b6b2260..7cbaae2 100644 --- a/android/src/main/java/com/rivereactnative/RiveReactNativeViewManager.kt +++ b/android/src/main/java/com/rivereactnative/RiveReactNativeViewManager.kt @@ -1,5 +1,6 @@ package com.rivereactnative +import android.util.Log import com.facebook.react.bridge.ReadableArray import com.facebook.react.common.MapBuilder import com.facebook.react.uimanager.SimpleViewManager @@ -55,7 +56,7 @@ class RiveReactNativeViewManager : SimpleViewManager() { } @ReactProp(name = "resourceName") - fun setResourceName(view: RiveReactNativeView, resourceName: String) { + fun setResourceName(view: RiveReactNativeView, resourceName: String?) { view.setResourceName(resourceName) } @@ -70,8 +71,8 @@ class RiveReactNativeViewManager : SimpleViewManager() { } @ReactProp(name = "url") - fun setUrl(view: RiveReactNativeView, url: String) { - view.setUrl(url) + fun setUrl(view: RiveReactNativeView, url: String?) { + view.setUrl(url) } @ReactProp(name = "autoplay") diff --git a/example/src/App.tsx b/example/src/App.tsx index 084f8cc..0ea8d93 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -6,10 +6,12 @@ import { TouchableOpacity, View, } from 'react-native'; -import Rive, { RiveRef, Fit } from 'rive-react-native'; +import Rive, { RiveRef, Fit, Alignment } from 'rive-react-native'; export default function App() { const [isPlaying, setPlaying] = React.useState(false); + const [fit, setFit] = React.useState(Fit.ScaleDown); + const [alignment, setAlignment] = React.useState(Alignment.TopCenter); const riveRef = React.useRef(null); @@ -27,6 +29,7 @@ export default function App() { { console.log('played animation name :', animationName, isStateMachine); @@ -49,7 +52,7 @@ export default function App() { ); }} style={styles.box} - fit={Fit.Contain} + fit={fit} resourceName={Platform.OS === 'android' ? 'flying_car' : 'bird'} // url={'https://cdn.rive.app/animations/juice_v7.riv'} /> @@ -57,6 +60,28 @@ export default function App() { {isPlaying ? 'PAUSE' : 'PLAY'} + + setFit((fitInner) => + fitInner === Fit.Contain ? Fit.ScaleDown : Fit.Contain + ) + } + > + Change FIT + + + setAlignment((fitInner) => + fitInner === Alignment.TopCenter + ? Alignment.BottomCenter + : Alignment.TopCenter + ) + } + > + Change Alignment + {Platform.OS === 'android' ? ( {'STOP'}