Dropdown in jetpack compose with Auto scroll to selected items

38 views Asked by At

I need to auto scroll to selected item when I open the dropdown. If there are 20 items in my list, I selected 18th item. Now I reopen the dropdown, it should show the selected item in dropdown view. But it's not happening.I made changes by using scrollState but it's not working.

This is my code I need to auto scroll to selected item when I open the dropdown. If there are 20 items in my list, I selected 18th item. Now I reopen the dropdown, it should show the selected item in dropdown view. But it's not happening.I made changes by using scrollState but it's not working.

@Composable
fun DropDownWithLabel(
    label: String, list: List<String>, previewWidth: Int = 80, expandedWidth: Int = 100,
    onSelected: (Int) -> Unit, defaultSelection: Int = 0,spacerLimit:Int=80,paddingLimit:Int=0,heightValue:Int=275) {
    Row {
        Box(modifier = Modifier.wrapContentWidth(), contentAlignment = Alignment.Center) {
            HeaderTextView(text = label, padding = paddingLimit)
        }

        Spacer(modifier = Modifier.width(spacerLimit.dp))

        var expanded by remember { mutableStateOf(false) }
        var selectedIndex by remember { mutableStateOf(defaultSelection) }
        Box(modifier = Modifier
                .width((previewWidth + 20).dp)
                .wrapContentSize(Alignment.TopStart)) {
            Column() {
                Row {
                    Text(
                        list[defaultSelection],
                        modifier = Modifier
                                .width((previewWidth).dp)
                                .height(35.dp)
                                .clickable(onClick = { expanded = true }),
                        fontSize = 22.sp,
                    )

                    Image(
                        painter = painterResource(id = R.drawable.angle_down_solid),
                        contentDescription = "Custom Icon",
                        modifier = Modifier
                                .size(30.dp)
                                .padding(PaddingValues(top = 8.dp)),
                        colorFilter = ColorFilter.tint(primaryColor)
                    )
                }
                Divider(color = Color.Gray)
            }
            var scrollState = rememberScrollState()
            DropdownMenu(
                expanded = expanded,
                onDismissRequest = { expanded = false },
                modifier = Modifier
                        .width((expandedWidth + 20).dp) //
                        .height(heightValue.dp)
                        .background(Color.White)
                        .border(0.5.dp, Color.LightGray)
                        .shadow(1.dp, shape = RoundedCornerShape(1.dp))
                        .scrollable(state = scrollState, orientation = Orientation.Vertical),
            ) {
                LaunchedEffect(expanded) {
                    CcuLog.d("sathish"," Entered in launched effect")
                    scrollState.animateScrollTo(selectedIndex)
                    scrollState.scrollTo(selectedIndex)
                  
                }

                    list.forEachIndexed { index, s ->

                        DropdownMenuItem(onClick = {
                            selectedIndex = index
                            expanded = false
                            onSelected(selectedIndex)
                        }, text = { Text(text = s, style = TextStyle(fontSize = 20.sp)) },
                                modifier = Modifier
                                        .background(if (index == selectedIndex) secondaryColor else                    Color.White),
                                contentPadding = PaddingValues(10.dp)
                        )
                    }

            }

        }
    }
}
2

There are 2 answers

2
BenjyTec On

The DropdownMenu Composable has a dedicated parameter where you can provide a scrollState:

@Composable
fun DropdownMenu( 
    expanded: Boolean,
    // ...
    scrollState: ScrollState = rememberScrollState(),
    // ...
    content: @Composable ColumnScope.() -> Unit
): Unit

Please update your code as follows:

val scrollState = rememberScrollState()
DropdownMenu(
    expanded = expanded,
    onDismissRequest = { expanded = false },
    modifier = Modifier
        .width((expandedWidth + 20).dp)
        .height(heightValue.dp)
        .background(Color.White)
        .border(0.5.dp, Color.LightGray)
        .shadow(1.dp, shape = RoundedCornerShape(1.dp)),  // remove scrollState here
    scrollState = scrollState   // use this parameter instead
) {
    //...
}

Also, I am not sure if using the LaunchedEffect within the DropdownMenu will work properly. If it still doesn't work, please move the LaunchedEffect next to the DropdownMenu like this:

val scrollState = rememberScrollState()
DropdownMenu(
    //...
    scrollState = scrollState
) {
    //...
}

LaunchedEffect(expanded) {
    if (expanded) {
        scrollState.animateScrollTo(selectedIndex)
        scrollState.scrollTo(selectedIndex)
    }
}
0
SATHISHKUMAR S On

@Composable fun DropDownWithLabel( label: String, list: List, previewWidth: Int = 80, expandedWidth: Int = 100, onSelected: (Int) -> Unit, defaultSelection: Int = 0,spacerLimit:Int=80,paddingLimit:Int=0,heightValue:Int=275) { Row { Box(modifier = Modifier.wrapContentWidth(), contentAlignment = Alignment.Center) { HeaderTextView(text = label, padding = paddingLimit) }

    Spacer(modifier = Modifier.width(spacerLimit.dp))

    var expanded by remember { mutableStateOf(false) }
    var selectedIndex by remember { mutableStateOf(defaultSelection) }
    var lazyListState = rememberLazyListState()
    Box(modifier = Modifier
        .width((previewWidth+20).dp)
        .wrapContentSize(Alignment.TopStart)) {
        Column() {
            Row {
                Text(
                    list[defaultSelection],
                    modifier = Modifier.width((previewWidth ).dp).height(35.dp)
                        .clickable(onClick = { expanded = true }),
                    fontSize = 22.sp,
                        maxLines = 1,
                      overflow = TextOverflow.Ellipsis
                )

                Image(
                    painter = painterResource(id = R.drawable.angle_down_solid),
                    contentDescription = "Custom Icon",
                    modifier = Modifier
                        .size(30.dp)
                        .padding(PaddingValues(top = 8.dp))
                        .clickable { expanded = true },
                    colorFilter = ColorFilter.tint(primaryColor)
                )
            }
            Divider(color = Color.Gray)
        }
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            modifier = Modifier
                .width((expandedWidth + 20).dp) //
                .height(heightValue.dp)
                .background(Color.White)
                .border(0.5.dp, Color.LightGray)
                .shadow(1.dp , shape = RoundedCornerShape(1.dp))
        ) {
              LazyColumn(state = lazyListState,
                      modifier = Modifier
                              .width((expandedWidth + 20).dp)
                              .height(heightValue.dp)) {

                  itemsIndexed(list) { index, s ->
                      DropdownMenuItem(onClick = {
                          selectedIndex = index
                          expanded = false
                          onSelected(selectedIndex) }, text = { Text(text = s, style = TextStyle(fontSize = 20.sp)) },
                          modifier = Modifier.background(if (index == selectedIndex) secondaryColor else Color.White),
                          contentPadding = PaddingValues(10.dp)
                      )
                   }
                }
            LaunchedEffect(expanded) {
                lazyListState.scrollToItem(selectedIndex, if(selectedIndex > 0) 40
                                                                          else 0)
            }
        }

    }
}

}

This is my code. Now it's auto scroll to seleceted position. But if I select the last item it doesn't scroll fully