Search code examples
androidkotlinandroid-layoutandroid-jetpack-composeandroid-jetpack

Extra padding in HorizontalPager


I'm trying to handle Horizontal Pager but I'm having a problem with additional padding from the top. It only happens when I add HorizontalPager() to my layout.

As you can see in the attachment I have grey indicators which I want to put below my pager but when I do that Pager goes lower and indicators become invisible. It looks like HorizontalPager() has some top padding (?)

Box(
    modifier = Modifier
        .fillMaxWidth()
        .height(350.dp)
        .clip(RoundedCornerShape(0.dp, 0.dp, 12.dp, 12.dp))
        .background(MaterialTheme.colors.onBackground)
) {
    ConstraintLayout(
        modifier = Modifier
            .fillMaxWidth()
            .wrapContentHeight()
            .padding(10.dp)
    ) {
        val (backButton, favouriteButton, photosPager) = createRefs()

        BackNavigationSingleButton(
            backButtonSelected = { }, modifier = Modifier
                .height(42.dp)
                .width(60.dp)
                .clip(RoundedCornerShape(10.dp))
                .background(Color.Red)
                .constrainAs(backButton) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                }
        )

        IconButton(onClick = {}, modifier = Modifier
            .size(42.dp)
            .constrainAs(favouriteButton) {
                top.linkTo(parent.top)
                end.linkTo(parent.end)
            }) {
            Icon(
                imageVector = Icons.Outlined.Favorite
            )
        }


        Column(
            modifier = Modifier
                .constrainAs(photosPager) {
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                    end.linkTo(parent.end)
                }) {
            val pagerState = rememberPagerState()
            val items = 3
            HorizontalPager(
                count = items,
                state = pagerState,
                contentPadding = PaddingValues(0.dp)
            ) { page ->
                Box(
                    modifier = Modifier
                        .size(100.dp)
                        .background(Color.Green)
                )
            }

            Row(modifier = Modifier.align(Alignment.CenterHorizontally)) {
                for (i in 1..items) {
                    Canvas(modifier = Modifier.size(20.dp)) {
                        drawCircle(
                            color =  Color.Gray,
                            center = Offset(x = 10f, y = 10f),
                            radius = size.minDimension / 4,
                        )
                    }
                }
            }
        }
    }
}


Solution

  • Each page inside HorizontalPager is using Modifier.fillParentMaxSize, which makes it fill all available height, same what Modifier.fillMaxHeight does.

    When Column has an item with Modifier.fillMaxHeight, this item will push all next items. To prevent this you can use Modifier.weight: in this case height of this view will be calculated after all other Column children.


    Also most of time ConstraintLayout is redundant in Compose, here's how you can build same layout without it:

    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(350.dp)
            .clip(RoundedCornerShape(0.dp, 0.dp, 12.dp, 12.dp))
            .background(MaterialTheme.colors.onBackground.copy(0.5f))
            .padding(10.dp)
    ) {
        Row {
            TextButton(
                onClick = { },
                modifier = Modifier
                    .clip(RoundedCornerShape(10.dp))
                    .background(Color.Red)
            ) {
                Text("button")
            }
            Spacer(Modifier.weight(1f))
            IconButton(
                onClick = {},
                modifier = Modifier
                    .size(42.dp)
            ) {
                Icon(
                    imageVector = Icons.Outlined.Favorite,
                    contentDescription = null
                )
            }
        }
    
        Column {
            val pagerState = rememberPagerState()
            val items = 3
            HorizontalPager(
                count = items,
                state = pagerState,
                contentPadding = PaddingValues(0.dp),
                modifier = Modifier.weight(1f)
            ) { page ->
                Box(
                    modifier = Modifier
                        .size(100.dp)
                        .background(Color.Green)
                )
            }
    
            Row(modifier = Modifier.align(Alignment.CenterHorizontally)) {
                for (i in 1..items) {
                    Canvas(modifier = Modifier.size(20.dp)) {
                        drawCircle(
                            color = Color.Gray,
                            center = Offset(x = 10f, y = 10f),
                            radius = size.minDimension / 4,
                        )
                    }
                }
            }
        }
    }
    

    Result: