繁体   English   中英

Jetpack Compose:在 DropDownMenu 中模仿 spinner.setSelection()

[英]Jetpack Compose: Mimicking spinner.setSelection() inside of a DropDownMenu

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

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

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

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

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

这是一个已知问题

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

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

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

如果您在 Android Studio 中,请单击鼠标悬停快速文档框上的三个点和 select “编辑源代码”以在 AndroidMenu.ZC31B32364CE19CA8FCD150A4CEECk 中打开DropdownMenu的源代码。 然后观察它使用了一个名为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}

       }
    }
}

上面只指定了如何访问DropdownMenuScrollState 但是一旦你有了ScrollState ,你就必须做一些算术才能让滚动 position 在它打开时正确。 这是一种看起来不错的方法。

计算滚动距离

即使在明确设置菜单项的内容之后,如果我依赖这些值,距离也永远不会完全正确。 因此,我在菜单项的Text中使用了onTextLayout回调,以便在渲染时获得真实的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
                 }
              }
              )

              }
          }
      }  
   }
}  

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM