Eang Tithsophorn
4 min readApr 5, 2023

Android Compose Horizontal pager with Indicator .
Automated scroll!

Hello guys , First of all my name is Eang Tithsophorn. I been working as Mobile Development for more than 3 year which are include Android , iOS and Flutter.

Here the list of my usage:

  • Kotlin
  • build.gradle (kts)
  • NetworkImage
  • Material3
  • Box (Stack)

First of all , we need this dependency from google itself!

implementation("androidx.compose.foundation:foundation:1.4.0")
implementation("io.coil-kt:coil-compose:2.2.2")// NetworkImage

Note : accompanist.pager already deprecated.

Just Follow the trend!

Incase you want to explore more for pager, Here is the doc.

Now let’s start , Shall we?

What’s if I tell you that all you need to run as a page?

HorizontalPager(
pageCount = yourList.size,
state = pagerState,
modifier = Modifier.height(300.dp)
) { index ->
AsyncImage(
model = yourList[index],
contentDescription = "this is image from server",
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
}
That’s it!

Note: AsyncImage is an compose function for request image from url which is doesn’t need the internet permission

You can play around with height and even with out you will notice something or some text!

Now it’s time for indicator!

val pagerState = rememberPagerState()

That’s where the controller of the page and indicator will be!

For Indicator

Row(
Modifier
.height(10.dp)
.fillMaxWidth()
.align(Alignment.BottomCenter),
horizontalArrangement = Arrangement.Center
) {
repeat(itemsList.size) { iteration ->
val color =
if (pagerState.currentPage == iteration) Color.Yellow else Color.LightGray
Box(
modifier = Modifier
.padding(start = 2.dp, end = 2.dp, bottom = 5.dp)
.clip(CircleShape)
.background(color)
.size(8.dp)
)
}
}

We style it a little bit and then we combine it all together!

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun BannerView(
modifier: Modifier = Modifier,
itemsList: List<String> = listOf(),
pagerState: PagerState = rememberPagerState()
) {

Card(
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
shape = RoundedCornerShape(8.dp),
modifier = modifier
) {
Box {
HorizontalPager(
pageCount = itemsList.size,
state = pagerState,
modifier = Modifier.height(300.dp)
) { index ->
AsyncImage(
model = itemsList[index],
contentDescription = "this is image from server",
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
}
Row(
Modifier
.height(10.dp)
.fillMaxWidth()
.align(Alignment.BottomCenter),
horizontalArrangement = Arrangement.Center
) {
repeat(itemsList.size) { iteration ->
val color =
if (pagerState.currentPage == iteration) appColor else Color.LightGray
Box(
modifier = Modifier
.padding(start = 2.dp, end = 2.dp, bottom = 5.dp)
.clip(CircleShape)
.background(color)
.size(8.dp)
)
}
}
}
}
}

Here the Result

Ohh lalalala!

I knew you want it auto scroll right?

I got you!

Here the code for auto scroll.

LaunchedEffect(key1 = pagerState.currentPage) {
launch {
delay(2000)
with(pagerState) {
val target = if (currentPage < itemsList.count() - 1) currentPage + 1 else 0

animateScrollToPage(
page = target, animationSpec = tween(
durationMillis = 0, easing = FastOutLinearInEasing
)
)
}
}
}

Full Code!!!!

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun BannerView(
modifier: Modifier = Modifier,
itemsList: List<String> = listOf(),
pagerState: PagerState = rememberPagerState()
) {

Card(
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp),
shape = RoundedCornerShape(8.dp),
modifier = modifier
) {
Box {
HorizontalPager(
pageCount = itemsList.size,
state = pagerState,
modifier = Modifier.height(300.dp)
) { index ->
AsyncImage(
model = itemsList[index],
contentDescription = "this is image from server",
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
}
Row(
Modifier
.height(10.dp)
.fillMaxWidth()
.align(Alignment.BottomCenter),
horizontalArrangement = Arrangement.Center
) {
repeat(itemsList.size) { iteration ->
val color =
if (pagerState.currentPage == iteration) Color.Yellow else Color.LightGray
Box(
modifier = Modifier
.padding(start = 2.dp, end = 2.dp, bottom = 5.dp)
.clip(CircleShape)
.background(color)
.size(8.dp)
)
}
}
}
}

LaunchedEffect(key1 = pagerState.currentPage) {
launch {
delay(2000)
with(pagerState) {
val target = if (currentPage < itemsList.count() - 1) currentPage + 1 else 0

animateScrollToPage(
page = target, animationSpec = tween(
durationMillis = 0, easing = FastOutLinearInEasing
)
)
}
}
}
}

How I call:

BannerView(
itemsList = listOf(
"https://images.pexels.com/photos/5110955/pexels-photo-5110955.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
"https://images.pexels.com/photos/3876443/pexels-photo-3876443.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
"https://images.pexels.com/photos/4284831/pexels-photo-4284831.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2",
"https://images.pexels.com/photos/4514301/pexels-photo-4514301.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2"
),
pagerState = pagerState,
modifier = Modifier.padding(start = 4.dp, end = 4.dp, bottom = 8.dp, top = 8.dp)
)
Here we goooo!

Thank you for your time!

I hope that’s it helpful in your case!

Leave a comment for check out more , git and my site.

See you in the next one!! :)

Eang Tithsophorn
Eang Tithsophorn

Written by Eang Tithsophorn

I am Mobile Development Learner. My mobile list box has Android , iOS and Flutter. More information http://128.199.87.161/

No responses yet