我正在寻找如何在Jetpack Compose中创建自定义对话框。在XML或Material Design中,我们可以轻松地创建自定义对话框,其中可以接受用户输入、单选按钮等等,但是我在Jetpack Compose中找不到类似的东西。
我正在寻找如何在Jetpack Compose中创建自定义对话框。在XML或Material Design中,我们可以轻松地创建自定义对话框,其中可以接受用户输入、单选按钮等等,但是我在Jetpack Compose中找不到类似的东西。
从M3 1.1.0-alpha04开始,有一个带有content
插槽的AlertDialog
组合函数。
val openDialog = remember { mutableStateOf(true) }
if (openDialog.value) {
androidx.compose.material3.AlertDialog(
onDismissRequest = {
// Dismiss the dialog when the user clicks outside the dialog or on the back
// button. If you want to disable that functionality, simply use an empty
// onDismissRequest.
openDialog.value = false
}
) {
Surface(
modifier = Modifier
.wrapContentWidth()
.wrapContentHeight(),
shape = MaterialTheme.shapes.large
) {
Column(modifier = Modifier.padding(16.dp)) {
//... AlertDialog content
}
}
}
}
在 M3 1.1.0-alpha04
之前或使用 M2,您可以使用标准 AlertDialog
。
text
、title
和 buttons
参数支持 @Composable
函数,这样您就可以根据自己的喜好自定义对话框。
例如:
val openDialog = remember { mutableStateOf(true) }
var text by remember { mutableStateOf("") }
if (openDialog.value) {
AlertDialog(
onDismissRequest = {
openDialog.value = false
},
title = {
Text(text = "Title")
},
text = {
Column() {
TextField(
value = text,
onValueChange = { text = it }
)
Text("Custom Text")
Checkbox(checked = false, onCheckedChange = {})
}
},
buttons = {
Row(
modifier = Modifier.padding(all = 8.dp),
horizontalArrangement = Arrangement.Center
) {
Button(
modifier = Modifier.fillMaxWidth(),
onClick = { openDialog.value = false }
) {
Text("Dismiss")
}
}
}
)
}
TextField
、Text
和 Checkbox
放在 text
参数里面吗?这是不符合直觉的。所以基本上除了确认和取消按钮之外,任何内容都应该放在那里吗? - kc_dev=
声明openDialog
,则必须使用.value.
。如果代之以by
, 则不得使用.value.
。 - MarianD这个示例演示了如何在安卓Jet Compose中制作自定义对话框。
阅读更多 https://www.boltuix.com/2022/01/ice-cream-app-ui-ux.html
import android.annotation.SuppressLint
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.compose.example.ui.theme.Pink80
import com.compose.example.ui.theme.Purple40
import com.compose.example.ui.theme.Purple80
import com.compose.example.ui.theme.PurpleGrey40
@Composable
fun CustomDialog(openDialogCustom: MutableState<Boolean>) {
Dialog(onDismissRequest = { openDialogCustom.value = false}) {
CustomDialogUI(openDialogCustom = openDialogCustom)
}
}
//Layout
@Composable
fun CustomDialogUI(modifier: Modifier = Modifier, openDialogCustom: MutableState<Boolean>){
Card(
//shape = MaterialTheme.shapes.medium,
shape = RoundedCornerShape(10.dp),
// modifier = modifier.size(280.dp, 240.dp)
modifier = Modifier.padding(10.dp,5.dp,10.dp,10.dp),
elevation = 8.dp
) {
Column(
modifier
.background(Color.White)) {
//.......................................................................
Image(
painter = painterResource(id = R.drawable.notification),
contentDescription = null, // decorative
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(
color = Purple40
),
modifier = Modifier
.padding(top = 35.dp)
.height(70.dp)
.fillMaxWidth(),
)
Column(modifier = Modifier.padding(16.dp)) {
androidx.compose.material3.Text(
text = "Get Updates",
textAlign = TextAlign.Center,
modifier = Modifier
.padding(top = 5.dp)
.fillMaxWidth(),
style = MaterialTheme.typography.labelLarge,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
androidx.compose.material3.Text(
text = "Allow Permission to send you notifications when new art styles added.",
textAlign = TextAlign.Center,
modifier = Modifier
.padding(top = 10.dp, start = 25.dp, end = 25.dp)
.fillMaxWidth(),
style = MaterialTheme.typography.bodyMedium
)
}
//.......................................................................
Row(
Modifier
.fillMaxWidth()
.padding(top = 10.dp)
.background(Purple80),
horizontalArrangement = Arrangement.SpaceAround) {
androidx.compose.material3.TextButton(onClick = {
openDialogCustom.value = false
}) {
androidx.compose.material3.Text(
"Not Now",
fontWeight = FontWeight.Bold,
color = PurpleGrey40,
modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)
)
}
androidx.compose.material3.TextButton(onClick = {
openDialogCustom.value = false
}) {
androidx.compose.material3.Text(
"Allow",
fontWeight = FontWeight.ExtraBold,
color = Color.Black,
modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)
)
}
}
}
}
}
@SuppressLint("UnrememberedMutableState")
@Preview (name="Custom Dialog")
@Composable
fun MyDialogUIPreview(){
CustomDialogUI(openDialogCustom = mutableStateOf(false))
}
Dialog(onDismissRequest = { openDialogCustom.value = false}) {
CustomDialogUI(openDialogCustom = openDialogCustom)
}
}
- Sadegh J还可以使用 lambda 将对话框中的值返回到任何其他组合中:
@Composable
private fun CustomDialogWithResultExample(
onDismiss: () -> Unit,
onNegativeClick: () -> Unit,
onPositiveClick: (Color) -> Unit
) {
var red by remember { mutableStateOf(0f) }
var green by remember { mutableStateOf(0f) }
var blue by remember { mutableStateOf(0f) }
val color = Color(
red = red.toInt(),
green = green.toInt(),
blue = blue.toInt(),
alpha = 255
)
Dialog(onDismissRequest = onDismiss) {
Card(
elevation = 8.dp,
shape = RoundedCornerShape(12.dp)
) {
Column(modifier = Modifier.padding(8.dp)) {
Text(
text = "Select Color",
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
modifier = Modifier.padding(8.dp)
)
Spacer(modifier = Modifier.height(8.dp))
// Color Selection
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Column {
Text(text = "Red ${red.toInt()}")
Slider(
value = red,
onValueChange = { red = it },
valueRange = 0f..255f,
onValueChangeFinished = {}
)
Spacer(modifier = Modifier.height(8.dp))
Text(text = "Green ${green.toInt()}")
Slider(
value = green,
onValueChange = { green = it },
valueRange = 0f..255f,
onValueChangeFinished = {}
)
Spacer(modifier = Modifier.height(8.dp))
Text(text = "Blue ${blue.toInt()}")
Slider(
value = blue,
onValueChange = { blue = it },
valueRange = 0f..255f,
onValueChangeFinished = {}
)
Spacer(modifier = Modifier.height(8.dp))
Surface(
border = BorderStroke(1.dp, Color.DarkGray),
color = color,
modifier = Modifier
.fillMaxWidth()
.height(40.dp)
) {}
}
}
// Buttons
Row(
horizontalArrangement = Arrangement.End,
modifier = Modifier.fillMaxWidth()
) {
TextButton(onClick = onNegativeClick) {
Text(text = "CANCEL")
}
Spacer(modifier = Modifier.width(4.dp))
TextButton(onClick = {
onPositiveClick(color)
}) {
Text(text = "OK")
}
}
}
}
}
}
并展示它
var showCustomDialogWithResult by remember { mutableStateOf(false) }
if (showCustomDialogWithResult) {
CustomDialogWithResultExample(
onDismiss = {
showCustomDialogWithResult = !showCustomDialogWithResult
Toast.makeText(context, "Dialog dismissed!", Toast.LENGTH_SHORT)
.show()
},
onNegativeClick = {
showCustomDialogWithResult = !showCustomDialogWithResult
Toast.makeText(context, "Negative Button Clicked!", Toast.LENGTH_SHORT)
.show()
},
onPositiveClick = { color ->
showCustomDialogWithResult = !showCustomDialogWithResult
Toast.makeText(context, "Selected color: $color", Toast.LENGTH_SHORT)
.show()
}
)
}
结果如下
我需要实现类似这样的效果:
将图片放在compose AlertDialog的“title”位置,将文本放在“text”位置,结果如下所示:
因为“title”和“text”被AlertDialogBaselineLayout包裹,导致添加了填充(padding),而我不知道该如何更改。
然而,“buttons”位置没有被包裹,我的解决方案是像以下代码一样(将“title”和“text”位置设置为null,所有对话框内容都放在“buttons”位置):
@Composable
fun AppDialog(
modifier: Modifier = Modifier,
dialogState: Boolean = false,
onDialogPositiveButtonClicked: (() -> Unit)? = null,
onDialogStateChange: ((Boolean) -> Unit)? = null,
onDismissRequest: (() -> Unit)? = null,
) {
val textPaddingAll = 24.dp
val buttonPaddingAll = 8.dp
val dialogShape = RoundedCornerShape(16.dp)
if (dialogState) {
AlertDialog(
onDismissRequest = {
onDialogStateChange?.invoke(false)
onDismissRequest?.invoke()
},
title = null,
text = null,
buttons = {
Column{
Image(
painter = painterResource(R.drawable.dialog_top_image),
contentDescription = "",
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth()
)
Row(Modifier.padding(all = textPaddingAll)){
TextWithHTMLSupport(
text = stringResource(R.string.gdprText)
)
}
Divider(color = MaterialTheme.colors.onSurface, thickness = 1.dp)
Row(
modifier = Modifier.padding(all = buttonPaddingAll),
horizontalArrangement = Arrangement.Center
) {
TextButton(
modifier = Modifier.fillMaxWidth(),
onClick = {
onDialogStateChange?.invoke(false)
onDialogPositiveButtonClicked?.invoke()
}
) {
Text(text = stringResource(R.string.dialog_ok), color = MaterialTheme.colors.onSurface)
}
}
}
},
properties = DialogProperties(dismissOnBackPress = true, dismissOnClickOutside = false),
modifier = modifier,
shape = dialogShape
)
}
}
要创建像这样的自定义对话框。
@Composable
fun CustomAlertDialog(onDismiss: () -> Unit, onExit: () -> Unit) {
Dialog(onDismissRequest = { onDismiss() }, properties = DialogProperties(
dismissOnBackPress = false,dismissOnClickOutside = false
)) {
Card(
//shape = MaterialTheme.shapes.medium,
shape = RoundedCornerShape(10.dp),
// modifier = modifier.size(280.dp, 240.dp)
modifier = Modifier
.fillMaxWidth()
.padding(8.dp),
elevation = 8.dp
) {
Column(
Modifier
.fillMaxWidth()
.background(Color.White)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.height(100.dp)
.background(Color.Red.copy(alpha = 0.8F)),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center,
) {
Image(
painter = painterResource(id = R.drawable.background_image),
contentDescription = "Exit app",
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.FillWidth
)
}
Text(
text = "Lorem Ipsum is simply dummy text",
modifier = Modifier.padding(8.dp), fontSize = 20.sp
)
Text(
text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard",
modifier = Modifier.padding(8.dp)
)
Row(Modifier.padding(top = 10.dp)) {
OutlinedButton(
onClick = { onDismiss() },
Modifier
.fillMaxWidth()
.padding(8.dp)
.weight(1F)
) {
Text(text = "Cancel")
}
Button(
onClick = { onExit() },
Modifier
.fillMaxWidth()
.padding(8.dp)
.weight(1F)
) {
Text(text = "Exit")
}
}
}
}
}
}
@Composable
fun Content() {
val context = LocalContext.current
var showCustomDialog by remember {
mutableStateOf(false)
}
Column(
Modifier.fillMaxSize(),
Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = { showCustomDialog = !showCustomDialog }, Modifier.wrapContentSize()) {
Text(text = "Show Alert Dialog")
}
}
if (showCustomDialog) {
CustomAlertDialog({
showCustomDialog = !showCustomDialog
}, {
val activity = (context as? Activity)
activity?.finish()
})
}
}
如上所述,我们需要使用Dialog()可组合函数来创建对话框。但对于输入字段,我们需要创建一个mutableStateOf()变量来保存输入字段的值。
@Composable
fun InputDialogView(onDismiss:() -> Unit) {
val context = LocalContext.current
var searchedFood by remember {
mutableStateOf("")
}
Dialog(onDismissRequest = { onDismiss() }) {
Card(
//shape = MaterialTheme.shapes.medium,
shape = RoundedCornerShape(10.dp),
// modifier = modifier.size(280.dp, 240.dp)
modifier = Modifier.padding(8.dp),
elevation = 8.dp
) {
Column(
Modifier
.background(Color.White)
) {
Text(
text = "Search your favorite food",
modifier = Modifier.padding(8.dp),
fontSize = 20.sp
)
OutlinedTextField(
value = searchedFood,
onValueChange = { searchedFood = it }, modifier = Modifier.padding(8.dp),
label = { Text("Favorite Food") }
)
Row {
OutlinedButton(
onClick = { onDismiss() },
Modifier
.fillMaxWidth()
.padding(8.dp)
.weight(1F)
) {
Text(text = "Cancel")
}
Button(
onClick = {
Toast.makeText(context, searchedFood, Toast.LENGTH_SHORT).show()
onDismiss() },
Modifier
.fillMaxWidth()
.padding(8.dp)
.weight(1F)
) {
Text(text = "Search")
}
}
}
}
}
}
对于加载对话框,我们需要使用CircularProgressIndicator()组合函数进行加载动画。除此之外,所有内容与其他自定义对话框相同。
@Composable
fun LoadingView(onDismiss:() -> Unit) {
Dialog(onDismissRequest = { onDismiss() }) {
Card(
shape = RoundedCornerShape(8.dp),
modifier = Modifier,
elevation = 8.dp
) {
Column(
Modifier
.background(Color.White)
.padding(12.dp)
) {
Text(
text = "Loading.. Please wait..",
Modifier
.padding(8.dp), textAlign = TextAlign.Center
)
CircularProgressIndicator(
strokeWidth = 4.dp,
modifier = Modifier
.align(Alignment.CenterHorizontally)
.padding(8.dp)
)
}
}
}
}
@Composable
fun CustomDialogScrollable(
onConfirmClicked: () -> Unit,
onDismiss: () -> Unit,
) {
Dialog(
onDismissRequest = onDismiss,
) {
Surface(
shape = MaterialTheme.shapes.medium,
color = MaterialTheme.colors.surface,
) {
Column(modifier = Modifier.padding(16.dp)) {
// TITLE
Text(text = "Title", style = MaterialTheme.typography.subtitle1)
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.weight(weight = 1f, fill = false)
.padding(vertical = 16.dp)
) {
Text(
text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s",
style = MaterialTheme.typography.body2
)
OutlinedTextField(value = "", onValueChange = {
}, Modifier.padding(top = 8.dp), label = { Text(text = "Email") })
// other content can go here
}
// BUTTONS
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
TextButton(onClick = onDismiss) {
Text(text = "Cancel")
}
TextButton(onClick = onConfirmClicked) {
Text(text = "OK")
}
}
}
}
}
}
val openDialog = remember { mutableStateOf(true) }
if (openDialog.value) {
CustomDialog({
// confirm clicked
}, {
openDialog.value = false
})
}
在Jetpack Compose中创建自定义对话框很容易。
这是一个询问启用两步验证的对话框。我还添加了点击事件。
输出:
代码:
查看更多带源代码的设计,请访问Jetpack Compose Samples
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
/*
For more designs with source code,
visit: https://semicolonspace.com/jetpack-compose-samples/
*/
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
BlogPostsTheme(darkTheme = false) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(color = MaterialTheme.colors.background),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
var openDialog by remember {
mutableStateOf(false) // Initially dialog is closed
}
ButtonClick(buttonText = "Open Dialog") {
openDialog = true
}
if (openDialog) {
DialogBox2FA {
openDialog = false
}
}
}
}
}
}
}
}
@Composable
fun DialogBox2FA(onDismiss: () -> Unit) {
val contextForToast = LocalContext.current.applicationContext
Dialog(
onDismissRequest = {
onDismiss()
}
) {
Surface(
modifier = Modifier
.fillMaxWidth(),
elevation = 4.dp
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(150.dp)
.background(color = Color(0xFF35898f)),
contentAlignment = Alignment.Center
) {
Image(
modifier = Modifier
.padding(top = 16.dp, bottom = 16.dp),
painter = painterResource(id = R.drawable.image_security),
contentDescription = "2-Step Verification",
alignment = Alignment.Center
)
}
Text(
modifier = Modifier.padding(top = 16.dp, bottom = 16.dp),
text = "2-Step Verification",
textAlign = TextAlign.Center,
style = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_bold, FontWeight.Bold)),
fontSize = 20.sp
)
)
Text(
modifier = Modifier.padding(start = 12.dp, end = 12.dp),
text = "Setup 2-Step Verification to add additional layer of security to your account.",
textAlign = TextAlign.Center,
style = TextStyle(
fontFamily = FontFamily(Font(R.font.roboto_regular, FontWeight.Normal)),
fontSize = 14.sp
)
)
Button(
modifier = Modifier
.fillMaxWidth()
.padding(top = 36.dp, start = 36.dp, end = 36.dp, bottom = 8.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = Color(0xFF35898f)),
onClick = {
onDismiss()
Toast.makeText(
contextForToast,
"Click: Setup Now",
Toast.LENGTH_SHORT
).show()
}) {
Text(
text = "Setup Now",
color = Color.White,
style = TextStyle(
fontFamily = FontFamily(
Font(
R.font.roboto_medium,
FontWeight.Medium
)
),
fontSize = 16.sp
)
)
}
TextButton(
onClick = {
onDismiss()
Toast.makeText(
contextForToast,
"Click: I'll Do It Later",
Toast.LENGTH_SHORT
).show()
}) {
Text(
text = "I'll Do It Later",
color = Color(0xFF35898f),
style = TextStyle(
fontFamily = FontFamily(
Font(
R.font.roboto_regular,
FontWeight.Normal
)
),
fontSize = 14.sp
)
)
}
}
}
}
}
@Composable
fun ButtonClick(
buttonText: String,
onButtonClick: () -> Unit
) {
Button(
shape = RoundedCornerShape(5.dp),
colors = ButtonDefaults.buttonColors(backgroundColor = MaterialTheme.colors.primary),
onClick = {
onButtonClick()
}) {
Text(
text = buttonText,
fontSize = 16.sp,
color = Color.White
)
}
}
谁想要使用像一样的自定义对话框。
@Composable
fun CustomAlertDialog(onDismiss: () -> Unit, onExit: () -> Unit) {
Dialog(
onDismissRequest = { onDismiss() }, properties = DialogProperties(
dismissOnBackPress = false, dismissOnClickOutside = false
)
) {
Card(
shape = RoundedCornerShape(10.dp),
modifier = Modifier
.fillMaxWidth().padding(0.dp).height(IntrinsicSize.Min),
elevation = 0.dp
) {
Column(
Modifier
.fillMaxWidth()
.background(Color.White)
) {
Text(
text = "Logout",
modifier = Modifier.padding(8.dp, 16.dp, 8.dp, 2.dp)
.align(Alignment.CenterHorizontally).fillMaxWidth(), fontSize = 20.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
Text(
text = "Are you sure you want to logout?",
modifier = Modifier.padding(8.dp, 2.dp, 8.dp, 16.dp)
.align(Alignment.CenterHorizontally).fillMaxWidth(),
textAlign = TextAlign.Center
)
Divider(color = Color.Gray, modifier = Modifier.fillMaxWidth().width(1.dp))
Row(Modifier.padding(top = 0.dp)) {
CompositionLocalProvider(
LocalMinimumTouchTargetEnforcement provides false,
) {
TextButton(
onClick = { onDismiss() },
Modifier
.fillMaxWidth()
.padding(0.dp)
.weight(1F)
.border(0.dp, Color.Transparent)
.height(48.dp),
elevation = ButtonDefaults.elevation(0.dp, 0.dp),
shape = RoundedCornerShape(0.dp),
contentPadding = PaddingValues(0.dp)
) {
Text(text = "Cancel", color = Color.Blue)
}
}
Divider(color = Color.Gray, modifier =
Modifier.fillMaxHeight().width(1.dp))
CompositionLocalProvider(
LocalMinimumTouchTargetEnforcement provides false,
) {
TextButton(
onClick = {
onExit.invoke()
},
Modifier
.fillMaxWidth()
.padding(0.dp)
.weight(1F)
.border(0.dp, color = Color.Transparent)
.height(48.dp),
elevation = ButtonDefaults.elevation(0.dp, 0.dp),
shape = RoundedCornerShape(0.dp),
contentPadding = PaddingValues()
) {
Text(text = "Logout", color = Color.Red)
}
}
}
}
}
}
}
并且可以在任何地方组合使用!
CustomAlertDialog(
onDismiss = {
/*do something*/
},
onExit = {
/*do something*/
})
class MainActivity : ComponentActivity() {
private val viewModel by lazy { MainViewModel() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourAppTheme {
HomeScreen(viewModel)
}
}
}
}
@Composable
fun HomeScreen(signUpViewModel: SignUpViewModel) {
Scaffold(
) { pd ->
//ignore
pd.calculateBottomPadding()
Column(
modifier = Modifier
.fillMaxSize()
.background(BackgroundColor)
.wrapContentSize(Alignment.Center)
.padding(20.dp)
) {
Spacer(modifier = Modifier.weight(1.0f)) // fill height with spacer
Text(
text = "HomeUI",
fontSize = 20.sp,
fontWeight = FontWeight(700),
color = Color(0xFF344054),
textAlign = TextAlign.Center,
modifier = Modifier
.align(alignment = CenterHorizontally)
.padding(0.dp)
)
Spacer(modifier = Modifier.fillMaxHeight(.1f))
CommonButton(buttonLabel = "Capture") {
signUpViewModel.showDialog.value = !signUpViewModel.showDialog.value
Log.e("error", "showDialog.value ${signUpViewModel.showDialog.value}")
}
if(signUpViewModel.showDialog.collectAsState().value)
CustomDialog(signUpViewModel = signUpViewModel)
Spacer(modifier = Modifier.weight(1.0f)) // fill height with spacer
}
}
}
对话界面: 毫不羞耻地从这里复制:SO答案
@Composable
fun CustomDialog(signUpViewModel: SignUpViewModel) {
Dialog(onDismissRequest = { signUpViewModel.showDialog.value = false }) {
CustomDialogUI(signUpViewModel = signUpViewModel)
}
}
//Layout
@Composable
fun CustomDialogUI(modifier: Modifier = Modifier, signUpViewModel: SignUpViewModel) {
Card(
//shape = MaterialTheme.shapes.medium,
shape = RoundedCornerShape(10.dp),
// modifier = modifier.size(280.dp, 240.dp)
modifier = Modifier.padding(10.dp, 5.dp, 10.dp, 10.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 20.dp)
// elevation = Shadow
) {
Column(
modifier.background(Color.White)
) {
//.......................................................................
Image(
painter = painterResource(id = R.drawable.ic_home),
contentDescription = null, // decorative
contentScale = ContentScale.Fit,
colorFilter = ColorFilter.tint(
color = PrimaryGreen
),
modifier = Modifier
.padding(top = 35.dp)
.height(70.dp)
.fillMaxWidth(),
)
Column(modifier = Modifier.padding(16.dp)) {
androidx.compose.material3.Text(
text = "Get Updates",
textAlign = TextAlign.Center,
modifier = Modifier
.padding(top = 5.dp)
.fillMaxWidth(),
style = MaterialTheme.typography.labelLarge,
maxLines = 2,
overflow = TextOverflow.Ellipsis
)
androidx.compose.material3.Text(
text = "Allow Permission to send you notifications when new art styles added.",
textAlign = TextAlign.Center,
modifier = Modifier
.padding(top = 10.dp, start = 25.dp, end = 25.dp)
.fillMaxWidth(),
style = MaterialTheme.typography.bodyMedium
)
}
//.......................................................................
Row(
Modifier
.fillMaxWidth()
.padding(top = 10.dp)
.background(PrimaryGreen),
horizontalArrangement = Arrangement.SpaceAround
) {
androidx.compose.material3.TextButton(onClick = {
signUpViewModel.showDialog.value = false
}) {
androidx.compose.material3.Text(
"Not Now",
fontWeight = FontWeight.Bold,
color = PrimaryGreen,
modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)
)
}
androidx.compose.material3.TextButton(onClick = {
signUpViewModel.showDialog.value = false
}) {
androidx.compose.material3.Text(
"Allow",
fontWeight = FontWeight.ExtraBold,
color = Color.Black,
modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)
)
}
}
}
}
}
ViewModel:
var showDialog = MutableStateFlow(false)
}