androidandroid-layoutandroid-jetpack-composeandroid-jetpack-compose-lazy-column

Android Jetpack Compose - Best way to handle scrolling of entire screen


My screen has a horizontal gallery at the top (LazyRow) and beneath it has a grid of 8 buttons that can be scrolled (LazyGrid).

Due to the layout the grid when scrolled doesn't affect the gallery which makes sense.

What I'd like to do however is for the entire screen to scroll when I scroll the menu, as I scroll up, the gallery should disappear out of view.

I am thinking that the only way that I can get this done is to change the root Column into a LazyColumn.

Is there a better way? Should I be using a surface instead?

I did try adding the following to the Column's Modifier but that made no difference since my grid is itself scrollable.

.scrollable(state = scrollState, orientation = Orientation.Vertical)

This is my current code:

@Composable
fun MainMenuScreen(imageGalleryPaths: List<String>, menuItemList: List<MenuItem>) {
    Column(
        modifier = Modifier
            .background(
                brush = Brush.verticalGradient(
                    colors = listOf(
                        MainMenuScreenBackgroundColorGradientStart,
                        MainMenuScreenBackgroundColorGradientEnd
                    )
                )
            )
    ) {
        HorizontalImageGallery(assetPaths = imageGalleryPaths)
        VerticalGridButtons(menuItems = menuItemList)
    }
}

@Composable
fun HorizontalImageGallery(assetPaths: List<String>) {
    LazyRow(modifier = Modifier.height(160.dp)) {
        items(assetPaths) { assetPath ->
            GalleryCard(assetPath)
        }
    }
}

@Composable
fun VerticalGridButtons(menuItems: List<MenuItem>) {
    LazyVerticalGrid(
        columns = GridCells.Fixed(2),
        contentPadding = PaddingValues(8.dp)
    ) {
        items(menuItems) { menuItem ->
            MenuItem(menuItem)
        }
    }
}

@Composable
fun GalleryCard(model: String) {
    Card(modifier = Modifier
        .padding(start = 0.dp, top = 10.dp, end = 10.dp, bottom = 10.dp)
        .fillMaxSize(),
        elevation = CardDefaults.cardElevation(defaultElevation = 8.dp),
        shape = RoundedCornerShape(8.dp)
    ) {
        AsyncImage(
            model = model,
            contentDescription = "Porsche Gallery Image",
            contentScale = ContentScale.FillBounds,
            modifier = Modifier
                .size(150.dp)
                .padding(4.dp)
        )
    }
}

Any guidance would greatly be appreciated.


Solution

  • To rewrite your code in a minimal example, it can be like this.

    @Composable
    fun ScrollableScreenDemo() {
        Column(
            modifier = Modifier,
        ) {
            HorizontalImageGallery()
            VerticalGridButtons()
        }
    }
    
    @Composable
    fun HorizontalImageGallery() {
        LazyRow {
            items(30) {
                Box(
                    modifier = Modifier
                        .padding(4.dp)
                        .size(30.dp)
                        .background(Color.LightGray),
                )
            }
        }
    }
    
    @Composable
    fun VerticalGridButtons() {
        LazyVerticalGrid(
            columns = GridCells.Fixed(2),
        ) {
            items(100) {
                Box(
                    modifier = Modifier
                        .padding(4.dp)
                        .size(30.dp)
                        .background(Color.DarkGray),
                )
            }
        }
    }
    

    To scroll the whole screen it can be rewritten like this,

    @Composable
    fun ScrollableScreenDemo() {
        VerticalGridButtons()
    }
    
    @Composable
    fun HorizontalImageGallery() {
        LazyRow {
            items(30) {
                Box(
                    modifier = Modifier
                        .padding(4.dp)
                        .size(30.dp)
                        .background(Color.LightGray),
                )
            }
        }
    }
    
    @Composable
    fun VerticalGridButtons() {
        LazyVerticalGrid(
            columns = GridCells.Fixed(2),
        ) {
            item(
                span = {
                    GridItemSpan(maxLineSpan)
                },
            ) {
                HorizontalImageGallery()
            }
            items(100) {
                Box(
                    modifier = Modifier
                        .padding(4.dp)
                        .size(30.dp)
                        .background(Color.DarkGray),
                )
            }
        }
    }
    

    Changes
    Make the LazyVerticalGrid the parent and have the HorizontalImageGallery inside it with GridItemSpan(maxLineSpan).