-
-
Save andrew-levy/a200152de34bd3382c536b8dc4ec6669 to your computer and use it in GitHub Desktop.
| 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 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
@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.
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)
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?