Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement horizontal scroller in android jetpack compose ui?

I'm trying to achieve a horizontal scroll view using jetpack compose like below:

Pic Of what I want

But I couldn't find any solution to set the width of cell to take width of screen with 16dp margin, and that's what I'm getting:

Pic Of what I'm getting

This the my code:

private val imageList : Array<Effect<Image>> =arrayOf(
        imageResource(R.drawable.maldive),
        imageResource(R.drawable.maldiveone),
        imageResource(R.drawable.maldivetwo))

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            createList()
        }


    }

    @Composable
    fun createList(){
        MaterialTheme() {
            HorizontalScroller(){
                Row(crossAxisSize = LayoutSize.Expand) {
                    (0..3).forEachIndexed { _, i ->
                            populateListItem(i)
                    }
                }
            }
        }
    }
    @Composable
    fun populateListItem(index: Int){
                Column(crossAxisSize = LayoutSize.Wrap, modifier = Spacing(16.dp)) {
                    Card(elevation = 0.dp, shape = RoundedCornerShape(8.dp, 8.dp, 8.dp, 8.dp)) {
                        val im: Image = +imageList[index.rem(3)]
                        Container(expanded = true,height = 180.dp)
                         {
                            DrawImage(image = im)
                        }
                    }
                    HeightSpacer(height = 16.dp)
                    Text("Maldive $index",
                        style = +themeTextStyle { h6 })
                    Text("Enjoy Our $index Resort!",
                        style = +themeTextStyle { body2 })
        }
    }
like image 785
Badran Avatar asked Oct 30 '19 21:10

Badran


People also ask

Does jetpack compose have a scrollable list?

Because Jetpack Compose is still in alpha, some source code may change with new versions. Jetpack Compose offers two ways each to display a scrollable list in vertical or horizontal: ScrollableColumn (resp. ScrollableRow) is a variant of Column (or Row) that scrolls when content is bigger than its height (or width).

What is scrollable modifier in jetpack?

In Android, the Scrollable Modifier detects the scroll gestures but does not offset its contents. Jetpack Compose supports nested scrolling, in which multiple elements react to a single scroll gesture. A typical example of nested scrolling is a list inside another list.

How to create a horizontal list in jetpack compose?

If you need a horizontal list, you just need to replace VerticalScroller with a HorizontalScroller and Column with a Row. Although this is how you create a list in Jetpack Compose but VerticalScroller feels like a ScrollView in my opinion.

What is Jetpack compose for Android?

Jetpack Compose is Android’s modern toolkit for building native UI. It simplifies and accelerates UI development on Android. Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs. Jetpack Compose is Android’s modern toolkit for building native UI.


2 Answers

The key is resources.displayMetrics.widthPixels, this will do the magic. replace your populateListItem function with below, it will work

@Composable
fun populateListItem(index: Int) {
    val padding = 16
    val dm = resources.displayMetrics
    val cardWidth = dm.widthPixels/dm.density - 16 * 2 // 2 is multiplied for left and right padding
    Column(crossAxisSize = LayoutSize.Wrap, modifier = Spacing(padding.dp)) {
        Card(elevation = 0.dp, shape = RoundedCornerShape(8.dp, 8.dp, 8.dp, 8.dp)) {
            val im: Image = +imageList[index.rem(3)]
            Container(width = cardWidth.dp, height = 180.dp)
            {
                DrawImage(image = im)
            }
        }
        HeightSpacer(height = 16.dp)
        Text("Maldive $index",
            style = +themeTextStyle { h6 })
        Text("Enjoy Our $index Resort!",
            style = +themeTextStyle { body2 })
    }
}
like image 120
Gopi S Avatar answered Oct 23 '22 05:10

Gopi S


Just adding my solution here...

@Composable
fun HorizontalScrollScreen() {
    // replace with your items...
    val items = (1..10).map { "Item $it" } 
    // a wrapper to fill the entire screen
    Box(modifier = Modifier.fillMaxSize()) { 
        // BowWithConstraints will provide the maxWidth used below
        BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
            // LazyRow to display your items horizontally
            LazyRow(
                modifier = Modifier.fillMaxWidth(),
                state = rememberLazyListState()
            ) {
                itemsIndexed(items) { index, item ->
                    Card(
                        modifier = Modifier
                            .height(100.dp)
                            .width(maxWidth) // here is the trick
                            .padding(16.dp)
                    ) {
                        Text(item) // card's content
                    }
                }
            }
        }
    }
}

This implementation works, but you will not have the snap behavior. This behavior is not supported out-of-the-box by LazyRow (there's a feature request for that https://issuetracker.google.com/issues/166590434), but you can try to implement this using the flingBehavior parameter.

Or for now, you can use the Accompanist Pager library. https://github.com/google/accompanist/tree/main/pager

like image 31
nglauber Avatar answered Oct 23 '22 05:10

nglauber