Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: set url prop and improved handling reloading logic #11

Merged
merged 5 commits into from
May 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 44 additions & 19 deletions android/src/main/java/com/rivereactnative/RiveReactNativeView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -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
Expand All @@ -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
}


Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -55,7 +56,7 @@ class RiveReactNativeViewManager : SimpleViewManager<RiveReactNativeView>() {
}

@ReactProp(name = "resourceName")
fun setResourceName(view: RiveReactNativeView, resourceName: String) {
fun setResourceName(view: RiveReactNativeView, resourceName: String?) {
view.setResourceName(resourceName)
}

Expand All @@ -70,8 +71,8 @@ class RiveReactNativeViewManager : SimpleViewManager<RiveReactNativeView>() {
}

@ReactProp(name = "url")
fun setUrl(view: RiveReactNativeView, url: String) {
view.setUrl(url)
fun setUrl(view: RiveReactNativeView, url: String?) {
view.setUrl(url)
}

@ReactProp(name = "autoplay")
Expand Down
29 changes: 27 additions & 2 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<RiveRef>(null);

Expand All @@ -27,6 +29,7 @@ export default function App() {
<View style={styles.container}>
<Rive
ref={riveRef}
alignment={alignment}
autoplay={false}
onPlay={(animationName, isStateMachine) => {
console.log('played animation name :', animationName, isStateMachine);
Expand All @@ -49,14 +52,36 @@ 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'}
/>
<View style={styles.wrapper}>
<TouchableOpacity onPress={toggleAnimation}>
<Text style={styles.button}>{isPlaying ? 'PAUSE' : 'PLAY'}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() =>
setFit((fitInner) =>
fitInner === Fit.Contain ? Fit.ScaleDown : Fit.Contain
)
}
>
<Text>Change FIT</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.button}
onPress={() =>
setAlignment((fitInner) =>
fitInner === Alignment.TopCenter
? Alignment.BottomCenter
: Alignment.TopCenter
)
}
>
<Text>Change Alignment</Text>
</TouchableOpacity>
{Platform.OS === 'android' ? (
<TouchableOpacity onPress={stopAnimation}>
<Text style={styles.button}>{'STOP'}</Text>
Expand Down