Skip to content

Commit 08abe4b

Browse files
authored
feat: add OpenGL ES renderer support for Android (#42)
* feat: add opt-in OpenGL ES renderer support for Android * chore: update dotlottie-android to v0.13.4
1 parent 07378b3 commit 08abe4b

6 files changed

Lines changed: 118 additions & 71 deletions

File tree

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ dependencies {
121121
//noinspection GradleDynamicVersion
122122
implementation "com.facebook.react:react-native:+"
123123
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
124-
implementation "com.github.LottieFiles:dotlottie-android:0.13.2"
124+
implementation "com.github.LottieFiles:dotlottie-android:0.13.4"
125125
implementation 'androidx.compose.ui:ui:1.5.0'
126126
implementation 'androidx.compose.material:material:1.5.0'
127127
implementation 'androidx.compose.ui:ui-tooling-preview:1.5.0'

android/src/main/java/com/dotlottiereactnative/DotlottieReactNativeView.kt

Lines changed: 106 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.dotlottiereactnative
33
import android.graphics.Color
44
import android.widget.FrameLayout
55
import androidx.compose.runtime.Composable
6+
import androidx.compose.runtime.mutableStateOf
67
import androidx.compose.ui.platform.ComposeView
78
import com.dotlottie.dlplayer.Mode
89
import com.facebook.react.bridge.Arguments
@@ -12,14 +13,15 @@ import com.facebook.react.uimanager.ThemedReactContext
1213
import com.facebook.react.uimanager.events.RCTEventEmitter
1314
import com.lottiefiles.dotlottie.core.compose.runtime.DotLottieController
1415
import com.lottiefiles.dotlottie.core.compose.ui.DotLottieAnimation
16+
import com.lottiefiles.dotlottie.core.compose.ui.DotLottieGLAnimation
1517
import com.lottiefiles.dotlottie.core.util.DotLottieEventListener
1618
import com.lottiefiles.dotlottie.core.util.DotLottieSource
1719
import com.lottiefiles.dotlottie.core.util.StateMachineEventListener
1820

1921
class DotlottieReactNativeView(context: ThemedReactContext) : FrameLayout(context) {
2022

2123
private var reactContext: ReactContext = context.reactApplicationContext
22-
private var animationUrl: String? = null
24+
private var animationUrl = mutableStateOf<String?>(null)
2325
private var loop: Boolean = false
2426
private var autoplay: Boolean = true
2527
private var speed: Float = 1f
@@ -29,7 +31,10 @@ class DotlottieReactNativeView(context: ThemedReactContext) : FrameLayout(contex
2931
private var segment: Pair<Float, Float>? = null
3032
private var playMode: Mode = Mode.FORWARD
3133
private var stateMachineId: String? = null
34+
private var useOpenGLRenderer: Boolean = false
35+
private var rendererLocked: Boolean = false
3236
var dotLottieController: DotLottieController = DotLottieController()
37+
private val eventListeners: List<DotLottieEventListener> = createEventListeners()
3338
private val stateMachineEventListener: StateMachineEventListener = createStateMachineEventListener()
3439
private var stateMachineListenerRegistered: Boolean = false
3540
private var hasActiveComposition: Boolean = false
@@ -51,81 +56,112 @@ class DotlottieReactNativeView(context: ThemedReactContext) : FrameLayout(contex
5156
reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, eventName, value)
5257
}
5358

59+
private fun createEventListeners(): List<DotLottieEventListener> {
60+
return listOf(
61+
object : DotLottieEventListener {
62+
override fun onLoad() {
63+
onReceiveNativeEvent("onLoad", null)
64+
}
65+
override fun onComplete() {
66+
onReceiveNativeEvent("onComplete", null)
67+
}
68+
override fun onLoadError() {
69+
onReceiveNativeEvent("onLoadError", null)
70+
}
71+
override fun onPlay() {
72+
onReceiveNativeEvent("onPlay", null)
73+
}
74+
override fun onStop() {
75+
onReceiveNativeEvent("onStop", null)
76+
}
77+
override fun onPause() {
78+
onReceiveNativeEvent("onPause", null)
79+
}
80+
override fun onFreeze() {
81+
onReceiveNativeEvent("onFreeze", null)
82+
}
83+
override fun onUnFreeze() {
84+
onReceiveNativeEvent("onUnFreeze", null)
85+
}
86+
override fun onDestroy() {
87+
onReceiveNativeEvent("onDestroy", null)
88+
}
89+
override fun onFrame(frame: Float) {
90+
val value =
91+
Arguments.createMap().apply {
92+
putDouble("frameNo", frame.toDouble())
93+
}
94+
onReceiveNativeEvent("onFrame", value)
95+
}
96+
override fun onLoop(loopCount: Int) {
97+
val value =
98+
Arguments.createMap().apply {
99+
putInt("loopCount", loopCount)
100+
}
101+
onReceiveNativeEvent("onLoop", value)
102+
}
103+
override fun onRender(frameNo: Float) {
104+
val value =
105+
Arguments.createMap().apply {
106+
putDouble("frameNo", frameNo.toDouble())
107+
}
108+
onReceiveNativeEvent("onRender", value)
109+
}
110+
}
111+
)
112+
}
113+
54114
@Composable
55115
fun DotLottieContent() {
56-
animationUrl?.let { url ->
57-
DotLottieAnimation(
58-
source = DotLottieSource.Url(url),
59-
autoplay = autoplay,
60-
loop = loop,
61-
speed = speed,
62-
controller = dotLottieController,
63-
useFrameInterpolation = useFrameInterpolation,
64-
themeId = themeId,
65-
stateMachineId = stateMachineId,
66-
marker = marker,
67-
segment = segment,
68-
playMode = playMode,
69-
eventListeners =
70-
listOf(
71-
object : DotLottieEventListener {
72-
override fun onLoad() {
73-
onReceiveNativeEvent("onLoad", null)
74-
}
75-
override fun onComplete() {
76-
onReceiveNativeEvent("onComplete", null)
77-
}
78-
override fun onLoadError() {
79-
onReceiveNativeEvent("onLoadError", null)
80-
}
81-
override fun onPlay() {
82-
onReceiveNativeEvent("onPlay", null)
83-
}
84-
override fun onStop() {
85-
onReceiveNativeEvent("onStop", null)
86-
}
87-
override fun onPause() {
88-
onReceiveNativeEvent("onPause", null)
89-
}
90-
override fun onFreeze() {
91-
onReceiveNativeEvent("onFreeze", null)
92-
}
93-
override fun onUnFreeze() {
94-
onReceiveNativeEvent("onUnFreeze", null)
95-
}
96-
override fun onDestroy() {
97-
onReceiveNativeEvent("onDestroy", null)
98-
}
99-
override fun onFrame(frame: Float) {
100-
val value =
101-
Arguments.createMap().apply {
102-
putDouble("frameNo", frame.toDouble())
103-
}
104-
onReceiveNativeEvent("onFrame", value)
105-
}
106-
override fun onLoop(loopCount: Int) {
107-
val value =
108-
Arguments.createMap().apply {
109-
putInt("loopCount", loopCount)
110-
}
111-
onReceiveNativeEvent("onLoop", value)
112-
}
113-
override fun onRender(frameNo: Float) {
114-
val value =
115-
Arguments.createMap().apply {
116-
putDouble("frameNo", frameNo.toDouble())
117-
}
118-
onReceiveNativeEvent("onRender", value)
119-
}
120-
}
121-
)
122-
)
116+
animationUrl.value?.let { url ->
117+
val source = DotLottieSource.Url(url)
118+
119+
if (useOpenGLRenderer) {
120+
DotLottieGLAnimation(
121+
source = source,
122+
autoplay = autoplay,
123+
loop = loop,
124+
speed = speed,
125+
controller = dotLottieController,
126+
useFrameInterpolation = useFrameInterpolation,
127+
themeId = themeId,
128+
stateMachineId = stateMachineId,
129+
marker = marker,
130+
segment = segment,
131+
playMode = playMode,
132+
eventListeners = eventListeners
133+
)
134+
} else {
135+
DotLottieAnimation(
136+
source = source,
137+
autoplay = autoplay,
138+
loop = loop,
139+
speed = speed,
140+
controller = dotLottieController,
141+
useFrameInterpolation = useFrameInterpolation,
142+
themeId = themeId,
143+
stateMachineId = stateMachineId,
144+
marker = marker,
145+
segment = segment,
146+
playMode = playMode,
147+
eventListeners = eventListeners
148+
)
149+
}
150+
}
151+
}
152+
153+
// Renderer is locked on first set because switching between GL and Canvas
154+
// surfaces at runtime is not supported by the underlying SDK.
155+
fun setUseOpenGLRenderer(value: Boolean) {
156+
if (!rendererLocked) {
157+
useOpenGLRenderer = value
158+
rendererLocked = true
123159
}
124160
}
125161

126162
fun setSource(url: String?) {
127-
animationUrl = url
128-
if (!isReleased) {
163+
animationUrl.value = url
164+
if (!isReleased && !hasActiveComposition) {
129165
renderContent()
130166
}
131167
}

android/src/main/java/com/dotlottiereactnative/DotlottieReactNativeViewManager.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ class DotlottieReactNativeViewManager : SimpleViewManager<DotlottieReactNativeVi
235235
view.setStateMachineId(value)
236236
}
237237

238+
@ReactProp(name = "renderer")
239+
fun setRenderer(view: DotlottieReactNativeView, value: String?) {
240+
view.setUseOpenGLRenderer(value == "gl")
241+
}
242+
238243
override fun onDropViewInstance(view: DotlottieReactNativeView) {
239244
super.onDropViewInstance(view)
240245
view.release()

example/examples/MultipleAnimationsTest.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export function MultipleAnimationsTest() {
3535
style={styles.animation}
3636
autoplay
3737
loop
38+
renderer='gl'
3839
/>
3940
</View>
4041
))}

src/DotLottie.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ export enum Mode {
3030
REVERSE_BOUNCE,
3131
}
3232

33+
export type Renderer = 'sw' | 'gl';
34+
3335
export type Dotlottie = {
3436
play: () => void;
3537
pause: () => void;
@@ -76,6 +78,7 @@ interface DotlottieNativeProps {
7678
playMode?: Mode;
7779
useFrameInterpolation?: boolean;
7880
stateMachineId?: string;
81+
renderer?: Renderer;
7982
style: ViewStyle;
8083
ref?: MutableRefObject<any>;
8184
onLoad?: () => void;
@@ -145,6 +148,7 @@ interface DotlottieReactNativeProps {
145148
playMode?: Mode;
146149
useFrameInterpolation?: boolean;
147150
stateMachineId?: string;
151+
renderer?: Renderer;
148152
style: ViewStyle;
149153
ref?: MutableRefObject<any>;
150154
onLoad?: () => void;

src/DotLottie.web.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ interface DotlottieReactNativeProps {
5656
playMode?: Mode;
5757
useFrameInterpolation?: boolean;
5858
stateMachineId?: string;
59+
renderer?: 'sw' | 'gl';
5960
style?: any;
6061
ref?: MutableRefObject<any>;
6162
onLoad?: () => void;

0 commit comments

Comments
 (0)