Skip to content

Instantly share code, notes, and snippets.

@andrew-levy
Last active April 11, 2024 05:03
Show Gist options
  • Save andrew-levy/a200152de34bd3382c536b8dc4ec6669 to your computer and use it in GitHub Desktop.
Save andrew-levy/a200152de34bd3382c536b8dc4ec6669 to your computer and use it in GitHub Desktop.
JetpackComposeViewModule
package expo.modules.jetpackcomposeview
import android.content.Context
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.unit.dp
import expo.modules.kotlin.AppContext
import expo.modules.kotlin.views.ExpoView
class JetpackComposeView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
internal val composeView = ComposeView(context).also {
// add the compose view as a child
addView(it)
it.layoutParams = LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
)
it.setContent {
Greeting("Compose")
}
}
// update the text
fun updateText(newValue: String) {
composeText.setContent {
Greeting(newValue)
}
}
}
// Composable here
@Composable
fun Greeting(name: String) {
var isChecked by remember { mutableStateOf(false) }
var isDialogOpen by remember { mutableStateOf(false) }
var sliderPosition by remember { mutableStateOf(0f) }
var animateText by remember { mutableStateOf(false) }
val scaleText by animateFloatAsState(targetValue = if (animateText) 1.5f else 1f, label = "")
val textColor by animateColorAsState(targetValue = if (animateText) Color.Blue else Color.Black, label = "")
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Expo + $name!",
style = MaterialTheme.typography.titleLarge,
color = textColor,
modifier = Modifier.graphicsLayer(scaleX = scaleText, scaleY = scaleText)
)
Button(
onClick = {
animateText = !animateText
},
modifier = Modifier.padding(16.dp)
) { Text(text = "Animate") }
Switch(
checked = isChecked,
onCheckedChange = { isChecked = it },
modifier = Modifier.padding(16.dp)
)
Slider(
value = sliderPosition,
onValueChange = { sliderPosition = it },
modifier = Modifier.padding(16.dp)
)
Button(
onClick = {
isDialogOpen = true
},
modifier = Modifier.padding(16.dp)
) {
Text(text = "Click Me")
}
if (isDialogOpen) {
AlertDialogExample(
onDismissRequest = {
isDialogOpen = false
},
onConfirmation = {
isDialogOpen = false
},
dialogTitle = "Dialog Title",
dialogText = "Dialog Text"
)
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AlertDialogExample(
onDismissRequest: () -> Unit,
onConfirmation: () -> Unit,
dialogTitle: String,
dialogText: String,
) {
AlertDialog(
title = {
Text(text = dialogTitle)
},
text = {
Text(text = dialogText)
},
onDismissRequest = {
onDismissRequest()
},
confirmButton = {
TextButton(
onClick = {
onConfirmation()
}
) {
Text("Confirm")
}
},
dismissButton = {
TextButton(
onClick = {
onDismissRequest()
}
) {
Text("Dismiss")
}
}
)
}
package expo.modules.jetpackcomposeview
import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
class JetpackComposeViewModule : Module() {
override fun definition() = ModuleDefinition {
Name("JetpackComposeView")
View(JetpackComposeView::class) {
Prop("name") { view: JetpackComposeView, prop: String ->
view.updateText(prop)
println(prop)
}
}
}
}
@corysimmons
Copy link

Very cool @andrew-levy ! 👏

I get errors about not being able to resolve Compose. Do you have instructions on adding those dependencies in an Expo project?

@andrew-levy
Copy link
Author

@corysimmons Thanks! You’ll need to add a bit of setup in your module’s build.gradle file. You can follow this: https://developer.android.com/jetpack/compose/setup

@ahmedsweng
Copy link

@corysimmons Thanks! You’ll need to add a bit of setup in your module’s build.gradle file. You can follow this: https://developer.android.com/jetpack/compose/setup

Hello @andrew-levy , can you please share with me the build.gradle file that you use to make jetpackCompose work with expo modules.

@andrew-levy
Copy link
Author

Module build.gradle example with compose:
https://github.com/andrew-levy/sweet-sheet/blob/main/android/build.gradle
(check the dependencies near the bottom)

Project build.gradle example:
https://github.com/andrew-levy/sweet-sheet/blob/main/example/android/build.gradle
(check line 22)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment