Roh*_*har 62 android android-alertdialog android-jetpack android-jetpack-compose android-compose-dialog
我正在搜索如何在 Jetpack Compose 中创建自定义对话框。在 XML 或 Material Design 中,我们可以轻松创建自定义对话框,在其中我们可以接受用户输入、单选按钮等,但我在 Jetpack Compose 中没有找到这样的东西。
Gab*_*tti 75
从M3 1.1.0-alpha04开始,有一个AlertDialog带有 .slot 的可组合函数content。
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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在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")
}
}
}
)
}
Run Code Online (Sandbox Code Playgroud)
Har*_*r S 42
这个例子演示了如何在 android 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))
}
Run Code Online (Sandbox Code Playgroud)
Thr*_*ian 20
还可以添加 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")
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
并显示它
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()
}
)
}
Run Code Online (Sandbox Code Playgroud)
结果是
Zor*_*ran 13
我必须实现这样的目标:
将图像放在“标题”插槽中,将文本放在“文本”插槽中,最后如下所示:
因为“标题”和“文本”是用添加填充的 AlertDialogBaselineLayout 包裹的,而且我不知道如何更改它。
但是,“按钮”插槽没有被包装,我的解决方案类似于以下代码(“标题”和“文本”插槽必须设置为空,所有对话框内容都进入“按钮”插槽):
@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
)
}
}
Run Code Online (Sandbox Code Playgroud)
小智 10
创建一个像这样的自定义对话框。
\n@Composable\nfun CustomAlertDialog(onDismiss: () -> Unit, onExit: () -> Unit) {\n\n Dialog(onDismissRequest = { onDismiss() }, properties = DialogProperties(\n dismissOnBackPress = false,dismissOnClickOutside = false\n )) {\n Card(\n //shape = MaterialTheme.shapes.medium,\n shape = RoundedCornerShape(10.dp),\n // modifier = modifier.size(280.dp, 240.dp)\n modifier = Modifier\n .fillMaxWidth()\n .padding(8.dp),\n elevation = 8.dp\n ) {\n Column(\n Modifier\n .fillMaxWidth()\n .background(Color.White)\n ) {\n\n\n Row(\n modifier = Modifier\n .fillMaxWidth()\n .height(100.dp)\n .background(Color.Red.copy(alpha = 0.8F)),\n verticalAlignment = Alignment.CenterVertically,\n horizontalArrangement = Arrangement.Center,\n\n ) {\n\n Image(\n painter = painterResource(id = R.drawable.background_image),\n contentDescription = "Exit app",\n modifier = Modifier.fillMaxSize(),\n contentScale = ContentScale.FillWidth\n )\n }\n\n Text(\n text = "Lorem Ipsum is simply dummy text",\n modifier = Modifier.padding(8.dp), fontSize = 20.sp\n )\n\n Text(\n text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard",\n modifier = Modifier.padding(8.dp)\n )\n\n Row(Modifier.padding(top = 10.dp)) {\n OutlinedButton(\n onClick = { onDismiss() },\n Modifier\n .fillMaxWidth()\n .padding(8.dp)\n .weight(1F)\n ) {\n Text(text = "Cancel")\n }\n\n\n Button(\n onClick = { onExit() },\n Modifier\n .fillMaxWidth()\n .padding(8.dp)\n .weight(1F)\n ) {\n Text(text = "Exit")\n }\n }\n\n\n }\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n现在我们已经创建了自定义对话框,要在单击按钮时显示对话框,您需要创建一个 mutableStateOf() 变量来维护对话框的显示和关闭状态。
\n另外,创建条件,例如如果变量为 true 则调用对话框,否则 don\xe2\x80\x99t 调用对话框函数。
\n@Composable\nfun Content() {\n val context = LocalContext.current\n var showCustomDialog by remember {\n mutableStateOf(false)\n }\n \n Column(\n Modifier.fillMaxSize(),\n Arrangement.Center,\n horizontalAlignment = Alignment.CenterHorizontally\n ) {\n Button(onClick = { showCustomDialog = !showCustomDialog }, Modifier.wrapContentSize()) {\n Text(text = "Show Alert Dialog")\n }\n\n\n }\n\n if (showCustomDialog) {\n CustomAlertDialog({\n showCustomDialog = !showCustomDialog\n }, {\n val activity = (context as? Activity)\n activity?.finish()\n })\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n单击对话框上的关闭按钮时,需要将变量更新为 false 以隐藏对话框。
\n代码的最终输出如下,
\n\n如上所述,我们需要使用 Dialog() 可组合函数创建对话框。但对于输入字段,我们需要创建一个 mutableStateOf() 变量来保存输入字段的值。
\n@Composable\nfun InputDialogView(onDismiss:() -> Unit) {\n val context = LocalContext.current\n var searchedFood by remember {\n mutableStateOf("")\n }\n\n Dialog(onDismissRequest = { onDismiss() }) {\n Card(\n //shape = MaterialTheme.shapes.medium,\n shape = RoundedCornerShape(10.dp),\n // modifier = modifier.size(280.dp, 240.dp)\n modifier = Modifier.padding(8.dp),\n elevation = 8.dp\n ) {\n Column(\n Modifier\n .background(Color.White)\n ) {\n\n Text(\n text = "Search your favorite food",\n modifier = Modifier.padding(8.dp),\n fontSize = 20.sp\n )\n\n OutlinedTextField(\n value = searchedFood,\n onValueChange = { searchedFood = it }, modifier = Modifier.padding(8.dp),\n label = { Text("Favorite Food") }\n )\n\n Row {\n OutlinedButton(\n onClick = { onDismiss() },\n Modifier\n .fillMaxWidth()\n .padding(8.dp)\n .weight(1F)\n ) {\n Text(text = "Cancel")\n }\n\n\n Button(\n onClick = {\n Toast.makeText(context, searchedFood, Toast.LENGTH_SHORT).show()\n onDismiss() },\n Modifier\n .fillMaxWidth()\n .padding(8.dp)\n .weight(1F)\n ) {\n Text(text = "Search")\n }\n }\n\n\n }\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n要显示该对话框,您需要按照上面相同的方式进行操作。通过创建 mutableStateOf() 变量并使其为 true 或 false。
\n上述代码的输出是,
\n\n对于加载对话框,我们需要使用 CircularProgressIndicator() 可组合函数来加载动画。除此之外,一切都与其他自定义对话框相同。
\n@Composable\nfun LoadingView(onDismiss:() -> Unit) {\n Dialog(onDismissRequest = { onDismiss() }) {\n\n Card(\n shape = RoundedCornerShape(8.dp),\n modifier = Modifier,\n elevation = 8.dp\n ) {\n Column(\n Modifier\n .background(Color.White)\n .padding(12.dp)\n ) {\n Text(\n text = "Loading.. Please wait..",\n Modifier\n .padding(8.dp), textAlign = TextAlign.Center\n )\n\n CircularProgressIndicator(\n strokeWidth = 4.dp,\n modifier = Modifier\n .align(Alignment.CenterHorizontally)\n .padding(8.dp)\n )\n }\n }\n }\n}\n\nRun Code Online (Sandbox Code Playgroud)\n关于加载对话框代码的输出,
\n\n如果自定义警报对话框的内容需要滚动(例如:横向模式或内容变长)。你可以这样做
@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")
}
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用
val openDialog = remember { mutableStateOf(true) }
if (openDialog.value) {
CustomDialog({
// confirm clicked
}, {
openDialog.value = false
})
}
Run Code Online (Sandbox Code Playgroud)
在 Jetpack Compose 中创建自定义对话框很容易。
这是一个对话框,要求启用两步验证。我还添加了点击事件。
输出:
代码:
有关更多带有源代码的设计,请参阅Jetpack Compose 示例
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
)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
73217 次 |
| 最近记录: |