点击右侧字母索引列时如何在屏幕中央显示放大首字母提示
实现方案
完全可以实现点击/滑动右侧字母索引时在屏幕中央显示放大选中字母的效果,核心是在布局上层加一个居中的提示浮层,仅在用户操作索引栏时展示,操作结束自动隐藏,仅需在原有代码基础上做少量修改:
- 新增两个状态变量:分别控制中央提示的显隐、存储当前选中的字母内容
- 补全右侧索引栏的手势逻辑:手指按下、滑动过程中显示提示,手指抬起/拖动取消时隐藏提示
- 将原有列表+索引栏的
Row布局嵌套进Box容器,在Box的层级上方添加居中的放大字母提示组件
改动后完整代码
enum class Items(@StringRes val nameId: Int, val typeId: Int) { Item1(R.string.apple, R.string.fruit), Item2(R.string.banana, R.string.fruit), Item3(R.string.cherry, R.string.fruit), Item4(R.string.date, R.string.fruit), Item5(R.string.eggplant, R.string.vegetable), Item6(R.string.fig, R.string.fruit), Item7(R.string.guava, R.string.fruit), Item8(R.string.jackfruit, R.string.fruit), Item9(R.string.kiwi, R.string.fruit), Item10(R.string.leek, R.string.vegetable), Item11(R.string.okra, R.string.vegetable), Item12(R.string.pumpkin, R.string.fruit), Item13(R.string.rhubarb, R.string.fruit), Item14(R.string.spinach, R.string.vegetable), Item15(R.string.turnip, R.string.vegetable), Item16(R.string.watermelon, R.string.fruit); } @Composable fun LetterIndexList() { val items = remember { arrayOf( Items.Item1, Items.Item2, Items.Item3, Items.Item4, Items.Item5, Items.Item6, Items.Item7, Items.Item8, Items.Item9, Items.Item10, Items.Item11, Items.Item12, Items.Item13, Items.Item14, Items.Item15, Items.Item16 ).sortedBy { getString(it.nameId) } } val headers = remember { items.map { getString(it.nameId).first().uppercase() }.toSet().toList() } // 新增:中央提示显隐状态、当前提示字母 var showIndexTip by remember { mutableStateOf(false) } var currentTipLetter by remember { mutableStateOf("") } Box(modifier = Modifier.fillMaxSize()) { Row { val listState = rememberLazyListState() LazyColumn( state = listState, modifier = Modifier.weight(1f) ) { items(items) { Column() { Text( text = stringResource(id = it.nameId) ) Text( text = stringResource(id = it.typeId) ) } } } val offsets = remember { mutableStateMapOf<Int, Float>() } var selectedHeaderIndex by remember { mutableStateOf(0) } val scope = rememberCoroutineScope() fun updateSelectedIndexIfNeeded(offset: Float) { val index = offsets .mapValues { abs(it.value - offset) } .entries .minByOrNull { it.value } ?.key ?: return if (selectedHeaderIndex == index) return selectedHeaderIndex = index // 新增:更新当前提示的字母 currentTipLetter = headers[selectedHeaderIndex] val selectedItemIndex = items.indexOfFirst { getString(it.nameId).first().uppercase() == headers[selectedHeaderIndex] } scope.launch { listState.scrollToItem(selectedItemIndex) } } Column( verticalArrangement = Arrangement.SpaceEvenly, modifier = Modifier .fillMaxHeight() .background(Color.Green) // 改动:补全点击手势的显隐逻辑 .pointerInput(Unit) { detectTapGestures( onPress = { showIndexTip = true awaitRelease() showIndexTip = false } ) { updateSelectedIndexIfNeeded(it.y) } } // 改动:补全拖动手势的显隐逻辑 .pointerInput(Unit) { detectVerticalDragGestures( onDragStart = { showIndexTip = true }, onDragEnd = { showIndexTip = false }, onDragCancel = { showIndexTip = false } ) { change, _ -> updateSelectedIndexIfNeeded(change.position.y) } } ) { headers.forEachIndexed { i, header -> Text( header, modifier = Modifier.onGloballyPositioned { offsets[i] = it.boundsInParent().center.y } ) } } } // 新增:屏幕中央放大字母提示 if (showIndexTip) { Box( modifier = Modifier .align(Alignment.Center) .size(80.dp) .background(Color.DarkGray, RoundedCornerShape(12.dp)), contentAlignment = Alignment.Center ) { Text( text = currentTipLetter, fontSize = 36.sp, color = Color.White, fontWeight = FontWeight.Bold ) } } } }
可自定义调整项
- 中央提示的尺寸、背景色、圆角、字体大小、字重都可以根据设计需求直接修改对应参数
- 如果需要更顺滑的展示效果,可以用
AnimatedVisibility包裹中央提示组件,添加淡入淡出、缩放的过渡动画 - 可以给提示增加额外的样式,比如加阴影、边框,匹配整体APP风格
内容的提问来源于stack exchange,提问作者wbk727
相关产品推荐
相关产品推荐

