Jetpack Compose中Autocomplete TextField展开致同行视图下移的修复
修复Jetpack Compose中AutoComplete TextField下拉面板导致同行视图偏移的问题
我在Jetpack Compose中实现了一个AutoComplete TextField,并将其放置在Row布局的两个视图之间。当自动补全下拉面板展开时,同行的其他视图会向下偏移,如何修复该问题?
原实现代码
@Composable fun AutoCompleteTextField( modifier: Modifier = Modifier, list: List<Product>, searchTerm: TextFieldValue, updateSearchTerm: (TextFieldValue) -> Unit, ) { var product by remember { mutableStateOf("") } var heightTextFields by remember { mutableStateOf(55.dp) } var textFieldSize by remember { mutableStateOf(Size.Zero) } var expanded by remember { mutableStateOf(false) } val interactionSource = remember { MutableInteractionSource() } Column( modifier = modifier .width(200.dp) .clickable( interactionSource = interactionSource, indication = null, onClick = { expanded = false } ) ) { Column(modifier = modifier.fillMaxWidth()) { Row( modifier = modifier .border(BorderStroke(width = 1.dp, color = Color.LightGray)) .fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { IconButton(onClick = {product = "" }) { Icon( imageVector = Icons.Filled.Add, contentDescription = "Add", modifier = modifier .padding(4.dp) .align(Alignment.CenterVertically) ) } TextField( modifier = Modifier .fillMaxWidth() .height(heightTextFields) .onGloballyPositioned { coordinates -> textFieldSize = coordinates.size.toSize() }, value = product, onValueChange = { product = it expanded = true }, colors = TextFieldDefaults.textFieldColors( backgroundColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, cursorColor = Color.Black ), textStyle = TextStyle( fontFamily = shabnamFontFamily, color = MaterialTheme.colorScheme.secondary, fontWeight = FontWeight.Bold, fontSize = 14.sp, ), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, imeAction = ImeAction.Done ), singleLine = true, ) } AnimatedVisibility(visible = expanded) { Card( modifier = modifier .padding(horizontal = 4.dp) .width(textFieldSize.width.dp), elevation = 10.dp, shape = RoundedCornerShape(bottomStart = 4.dp, bottomEnd = 4.dp) ) { LazyColumn( modifier = Modifier.heightIn(max = 150.dp), ) { if (product.isNotEmpty()) { items( list.filter { it.productName.lowercase() .contains(product.lowercase()) } ) { item -> ProductItems(title = item.productName) { title -> product = title expanded = false } } } else { items( items = list ) { item -> ProductItems(title = item.productName) { title -> product = title expanded = false } } } } } } } } }
问题原因
当前的下拉面板通过AnimatedVisibility嵌套在Column布局中,属于布局流的一部分。当面板展开时,会增加所在Column的高度,导致整个AutoCompleteTextField组件的高度被撑开,进而推动所在Row中的其他视图向下偏移。
修复方案
使用Jetpack Compose的Popup组件承载下拉列表,让下拉面板悬浮在原有布局上方,脱离布局流,这样就不会影响同行视图的位置。
修改后的代码
@Composable fun AutoCompleteTextField( modifier: Modifier = Modifier, list: List<Product>, searchTerm: TextFieldValue, updateSearchTerm: (TextFieldValue) -> Unit, ) { var product by remember { mutableStateOf("") } var heightTextFields by remember { mutableStateOf(55.dp) } var textFieldBounds by remember { mutableStateOf(Rect.Zero) } var expanded by remember { mutableStateOf(false) } val interactionSource = remember { MutableInteractionSource() } Box( modifier = modifier .width(200.dp) .clickable( interactionSource = interactionSource, indication = null, onClick = { expanded = false } ) ) { Row( modifier = modifier .border(BorderStroke(width = 1.dp, color = Color.LightGray)) .fillMaxWidth() .onGloballyPositioned { coordinates -> // 获取TextField所在Row的全局位置信息 textFieldBounds = coordinates.boundsInWindow() }, verticalAlignment = Alignment.CenterVertically ) { IconButton(onClick = { product = "" }) { Icon( imageVector = Icons.Filled.Add, contentDescription = "Add", modifier = modifier .padding(4.dp) .align(Alignment.CenterVertically) ) } TextField( modifier = Modifier .fillMaxWidth() .height(heightTextFields), value = product, onValueChange = { product = it expanded = true }, colors = TextFieldDefaults.textFieldColors( backgroundColor = Color.Transparent, focusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent, cursorColor = Color.Black ), textStyle = TextStyle( fontFamily = shabnamFontFamily, color = MaterialTheme.colorScheme.secondary, fontWeight = FontWeight.Bold, fontSize = 14.sp, ), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, imeAction = ImeAction.Done ), singleLine = true, ) } // 使用Popup承载下拉列表 Popup( onDismissRequest = { expanded = false }, // 设置Popup的位置为TextField下方 offset = IntOffset( x = textFieldBounds.left.roundToInt(), y = textFieldBounds.bottom.roundToInt() ) ) { if (expanded) { Card( modifier = Modifier .padding(horizontal = 4.dp) .width(textFieldBounds.width.dp), elevation = 10.dp, shape = RoundedCornerShape(bottomStart = 4.dp, bottomEnd = 4.dp) ) { LazyColumn( modifier = Modifier.heightIn(max = 150.dp), ) { val filteredList = if (product.isNotEmpty()) { list.filter { it.productName.lowercase() .contains(product.lowercase()) } } else { list } items(filteredList) { item -> ProductItems(title = item.productName) { title -> product = title expanded = false } } } } } } } }
关键修改点
- 将外层的Column替换为Box,方便Popup定位
- 使用
onGloballyPositioned获取TextField所在Row的全局边界信息,用于Popup的位置计算 - 用
Popup替代AnimatedVisibility承载下拉面板,让面板悬浮在布局上方,不占用布局流空间 - 调整Popup的偏移量,使其精准显示在TextField下方
内容的提问来源于stack exchange,提问作者Saeed Noshadi
相关产品推荐
相关产品推荐

