如何实现AlertDialog打开时预填充OutlinedTextField并保留输入数据?
实现方案(Jetpack Compose + Node.js + Postgres)
一、Jetpack Compose 前端实现
1. 管理报告表单状态
用remember和mutableStateOf绑定表单数据,确保AlertDialog关闭/页面重组时数据不丢失:
data class ReportForm( val title: String = "", val description: String = "", val category: String = "", val severity: String = "", val lat: Double? = null, val lng: Double? = null ) @Composable fun ReportScreen() { var showDialog by remember { mutableStateOf(false) } var reportForm by remember { mutableStateOf(ReportForm()) } val navController = rememberNavController() // 监听地图页面返回的更新表单 LaunchedEffect(navController) { navController.currentBackStackEntry?.savedStateHandle?.getLiveData<ReportForm>("updatedForm")?.observeForever { reportForm = it showDialog = true // 返回后保持Dialog打开 } } // 打开Dialog的FAB FloatingActionButton(onClick = { showDialog = true }) { Icon(Icons.Default.Add, contentDescription = "新建报告") } if (showDialog) { AlertDialog( onDismissRequest = { showDialog = false }, title = { Text("创建报告") }, text = { Column(spacing = 16.dp) { OutlinedTextField( value = reportForm.title, onValueChange = { reportForm = reportForm.copy(title = it) }, label = { Text("标题") } ) OutlinedTextField( value = reportForm.description, onValueChange = { reportForm = reportForm.copy(description = it) }, label = { Text("描述") } ) // 分类下拉选单、严重程度单选组可按需实现,逻辑类似 } }, confirmButton = { Button(onClick = { // 跳转地图页,传递当前表单数据 navController.navigate("map_screen?form=${Gson().toJson(reportForm)}") }) { Text("选择位置") } }, dismissButton = { Button(onClick = { showDialog = false }) { Text("取消") } }, additionalButtons = { // 可选:添加最终提交按钮,需校验经纬度是否存在 Button( onClick = { if (reportForm.lat != null && reportForm.lng != null) { saveFullReport(reportForm) showDialog = false reportForm = ReportForm() // 重置表单 } }, enabled = reportForm.title.isNotEmpty() && reportForm.lat != null ) { Text("提交报告") } } ) } }
2. 地图页面(支持拖动标记选位)
集成Google Map组件,监听标记拖动事件获取经纬度,点击保存后返回原页面并更新表单:
@Composable fun MapScreen(navController: NavHostController, formJson: String?) { val initialForm = remember { formJson?.let { Gson().fromJson(it, ReportForm::class.java) } ?: ReportForm() } var selectedLatLng by remember { mutableStateOf(LatLng(39.9042, 116.4074)) } // 默认坐标 GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(selectedLatLng, 15f) } ) { Marker( position = selectedLatLng, draggable = true, onDragEnd = { newPos -> selectedLatLng = newPos } ) } // 底部保存按钮 Box(Modifier.fillMaxSize().padding(16.dp), contentAlignment = Alignment.BottomCenter) { Button(onClick = { val updatedForm = initialForm.copy( lat = selectedLatLng.latitude, lng = selectedLatLng.longitude ) // 调用后端接口保存经纬度(可选:也可最后提交完整报告时再存) saveLocationToBackend(updatedForm) // 返回原页面并传递更新后的表单 navController.previousBackStackEntry?.savedStateHandle?.set("updatedForm", updatedForm) navController.popBackStack() }) { Text("保存位置") } } }
3. 网络请求工具类示例
封装简单的POST请求:
suspend fun saveLocationToBackend(form: ReportForm) { val client = OkHttpClient() val body = FormBody.Builder() .add("title", form.title) .add("lat", form.lat.toString()) .add("lng", form.lng.toString()) .build() val request = Request.Builder() .url("http://your-backend-url/api/reports/location") .post(body) .build() client.newCall(request).execute() }
二、Node.js + Postgres 后端实现
1. 创建数据库表
CREATE TABLE reports ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, description TEXT, category VARCHAR(100), severity VARCHAR(50), lat DOUBLE PRECISION NOT NULL, lng DOUBLE PRECISION NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
2. 编写API接口
用Express和pg库实现:
const express = require('express'); const { Pool } = require('pg'); const app = express(); app.use(express.json()); // 连接Postgres const pool = new Pool({ user: 'postgres', host: 'localhost', database: 'report_db', password: 'your-password', port: 5432, }); // 分步保存位置(或完整报告) app.post('/api/reports/location', async (req, res) => { const { title, lat, lng } = req.body; try { // 若先创建报告草稿,可先插入基础数据再更新;此处直接插入完整数据示例 await pool.query( 'INSERT INTO reports (title, lat, lng) VALUES ($1, $2, $3)', [title, lat, lng] ); res.status(200).json({ message: "位置已保存" }); } catch (err) { console.error(err); res.status(500).json({ error: "保存失败" }); } }); // 提交完整报告接口 app.post('/api/reports', async (req, res) => { const { title, description, category, severity, lat, lng } = req.body; try { const result = await pool.query( 'INSERT INTO reports (title, description, category, severity, lat, lng) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *', [title, description, category, severity, lat, lng] ); res.status(201).json(result.rows[0]); } catch (err) { console.error(err); res.status(500).json({ error: "提交失败" }); } }); app.listen(3000, () => console.log('后端服务运行在3000端口'));
三、关键注意事项
- 状态持久化:依赖Compose的
remember和Navigation的savedStateHandle传递数据,避免使用全局变量导致状态混乱。 - 地图权限:需在AndroidManifest.xml中添加位置权限和Google Maps API密钥。
- 错误处理:前端需处理网络请求失败、权限拒绝等异常场景,给用户提示。
- 分步/完整提交:可根据业务需求选择先保存位置再补全其他信息,或最后一次性提交完整报告。
内容的提问来源于stack exchange,提问作者alsabih
相关产品推荐
相关产品推荐

