0

用例是您在下拉菜单中有 10 或 100 项,下拉选项有一些排序 - 如数字值或单词的字母列表 - 并且选择是连续进行的。

当用户重新打开菜单时,您希望它在与他们上次选择的区域相同的区域中打开,例如,您不会从“car”跳转到“apple”,而是从“car”跳转到“cat” ”。或者,如果他们只是选择查看订单号 358,他们可以快速查看订单号 359。

使用视图,您可以创建一个Spinner并将所有项目放在一个中ArrayAdapter,然后调用spinner.setSelection()以直接滚动到您想要的索引。

DropdownMenu没有像HorizontalPager's这样的东西scrollToPage()。那么可能存在哪些解决方案来实现这一目标呢?

到目前为止,我已经尝试添加verticalScroll()DropdownMenu' 修饰符并尝试使用 scrollState 进行算术运算。但它在运行时崩溃,并显示该组件具有无限高度的错误,如果您尝试嵌套可滚动组件(如带有 verticalScroll的LazyColumn内部),则会出现相同的错误。Column

4

2 回答 2

1

这是一个已知问题

DropdownMenu 内部有自己的垂直滚动修饰符,并且没有 API 可以使用它。

在通过提供合适的 API 解决此问题之前,我能想到的唯一解决方法是创建自己的视图 - 您可以将源代码DropdownMenu作为参考。

于 2022-01-25T06:31:21.060 回答
0

我将在这里发布更详细的答案,因为我不想用上面的评论误导任何人。

如果您在 Android Studio 中,请单击鼠标悬停快速文档框上的三个点,然后选择“编辑源”以打开DropdownMenuAndroidMenu.android.kt 中的源。然后观察它使用了一个名为DropdownMenuItemContent. 再次编辑源代码,您将在 Menu.kt 中。

你会看到这个:

@Composable
internal fun DropdownMenuContent(
...
...
...
{
        Column(
            modifier = modifier
                .padding(vertical = DropdownMenuVerticalPadding)
                .width(IntrinsicSize.Max)
                .verticalScroll(rememberScrollState()),//<-We want this
            content = content
        )
    }

因此,在您的自定义可组合中,只需将其替换rememberScrollState()为您最喜欢的 ScrollState 变量名称即可。

然后将该引用一直链接到您的原始视图。

访问 ScrollState

@Composable 
fun MyCustomDropdownMenu(
    expanded:Boolean,
    scrollStateProvidedByTopParent:ScrollState,
    ...
    ...
   )
   {...}

@Composable
fun MyCustomDropdownMenuContent(
    scrollStateProvidedByTopParent:ScrollState,
    ...
    ...
    )
    {...}


//And now for your actual content

@Composable
fun TopParent(){
    val scrollStateProvidedByTopParent=rememberScrollState()
    val spinnerExpanded by remember{mutableStateOf(false)}
    ...
    ...
    Box{
       Row(modifier=Modifier.clickable(onClick={spinnerExpanded=!spinnerExpanded}))//<-More about this line in the sequel
    {
      Text("Options")
      Icon(imageVector = Icons.Filled.ArrowDropDown, contentDescription = "")
      
      MyCustomDropdownMenu(
      expanded = spinnerExpanded,
      scrollStateProvidedByTopParent=scrollStateProvidedByTopParent,
      onDismissRequest = { spinnerExpanded = false }) 
    {//your spinner content}

       }
    }
}

以上仅指定如何访问ScrollState. DropdownMenu但是一旦你有了ScrollState,你就必须做一些算术才能在它打开时得到正确的滚动位置。这是一种看起来不错的方法。

计算滚动距离

即使在明确设置菜单项的内容之后,如果我依赖这些值,距离也永远不会完全正确。所以我onTextLayout在我的菜单项中使用了一个回调Text,以便Text在渲染时获得真实的高度。然后我将该值用于算术。它看起来像这样:

@Composable
fun TopParent(){
    val scrollStateProvidedByTopParent=rememberScrollState()
    val spinnerExpanded by remember{mutableStateOf(false)}
    val chosenText:String by remember{mutableStateOf(myListOfSpinnerOptions[0])
    val height by remember{mutableStateOf(0)}
    val heightHasBeenChecked by remember{mutableStateOf(false)}
    val coroutineScope=rememberCoroutineScope()

    ...
    ...
    Box{
       Row(modifier=Modifier.clickable(onClick={spinnerExpanded=!spinnerExpanded
 coroutineScope.launch{scrollStateProvidedByTopParent.scrollTo(height*myListOfSpinnerOptions.indexOf[chosenText])}}))//<-This gets some arithmetic for scrolling distance
    {
      Text("Options")
      Icon(imageVector = Icons.Filled.ArrowDropDown, contentDescription = "")
          
      MyCustomDropdownMenu(
      expanded = spinnerExpanded,
      scrollStateProvidedByTopParent=scrollStateProvidedByTopParent,
      onDismissRequest = { spinnerExpanded = false }) {
        myListOfSpinnerOptions.forEach{option->  
        DropdownMenuItem(onClick={
            chosenText=option    
            spinnerExpanded=false
            }){
              Text(option,onTextLayout={layoutResult->
              if (!heightHasBeenChecked){
                 height=layoutResults.size.height
                 heightHasBeenChecked=true
                 }
              }
              )

              }
          }
      }  
   }
}  
于 2022-01-25T13:23:20.943 回答