Dots indicators for Android ViewPager and Compose
Kotlin
3,604
240 commits
updated Oct 11, 2026
Dots Indicator is an Android library for Jetpack Compose and classic XML views 🚀
Compose support is built into the same artifact and exposes four indicator types: Shift, Spring, Worm, and Balloon.
Don't forget to star the project if you like it!
== 
Feel free to submit issues and enhancement requests!
Add Maven Central and the library dependency:
repositories {
google()
mavenCentral()
}
dependencies {
implementation("com.tbuonomo:dotsindicator:5.1.2")
}
DotsIndicator works directly with androidx.compose.foundation.pager.PagerState.
DotsIndicator(
dotCount = pageCount,
type = ShiftIndicatorType(
dotsGraphic = DotGraphic(color = MaterialTheme.colorScheme.primary)
),
pagerState = pagerState
)
DotsIndicator(
dotCount = pageCount,
type = SpringIndicatorType(
dotsGraphic = DotGraphic(
size = 16.dp,
borderWidth = 2.dp,
borderColor = MaterialTheme.colorScheme.primary,
color = Color.Transparent
),
selectorDotGraphic = DotGraphic(
size = 14.dp,
color = MaterialTheme.colorScheme.primary
)
),
pagerState = pagerState
)
DotsIndicator(
dotCount = pageCount,
type = WormIndicatorType(
dotsGraphic = DotGraphic(
size = 16.dp,
borderWidth = 2.dp,
borderColor = MaterialTheme.colorScheme.primary,
color = Color.Transparent,
),
wormDotGraphic = DotGraphic(
size = 16.dp,
color = MaterialTheme.colorScheme.primary,
)
),
pagerState = pagerState
)
DotsIndicator(
dotCount = pageCount,
type = BalloonIndicatorType(
dotsGraphic = DotGraphic(
size = 8.dp,
color = MaterialTheme.colorScheme.primary
),
balloonSizeFactor = 2f
),
dotSpacing = 20.dp,
pagerState = pagerState
)
Classic Android views are still supported for ViewPager and ViewPager2 with attachTo(...).

<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
android:id="@+id/dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dotsColor="@color/material_white"
app:dotsCornerRadius="8dp"
app:dotsElevation="4dp"
app:dotsSize="16dp"
app:dotsSpacing="4dp"
app:dotsWidthFactor="2.5"
app:selectedDotColor="@color/md_blue_200"
app:progressMode="true"
app:dotsClickable="true" />
| Attribute | Description |
|---|---|
dotsColor | Color of the dots |
selectedDotColor | Color of the selected dot (defaults to dotsColor) |
progressMode | Colors every previous dot with the selected dot color |
dotsSize | Size of the dots (default: 16dp) |
dotsSpacing | Space between dots (default: 8dp) |
dotsWidthFactor | Width multiplier for the selected dot (default: 2.5) |
dotsCornerRadius | Dot corner radius (defaults to half of dotsSize) |
dotsElevation | Elevation applied to the dots |
dotsClickable | Enables changing page when a dot is tapped (default: true) |
val dotsIndicator = findViewById<DotsIndicator>(R.id.dots_indicator)
val viewPager = findViewById<ViewPager2>(R.id.view_pager)
viewPager.adapter = ViewPagerAdapter()
dotsIndicator.attachTo(viewPager)
Give each dot its own selected and/or unselected color. Indices beyond the array length fall back to the global selectedDotColor / dotsColor. Empty arrays use the global colors, and assigning null restores them. Assigning an array refreshes existing dots; after changing an array element, reassign the array to repaint. In progressMode, passed dots retain their own selected color. This API applies only to the classic View-based DotsIndicator.
// Each dot lights up in a different accent color when selected
dotsIndicator.selectedDotColors = intArrayOf(
Color.parseColor("#FF5252"), // dot 0
Color.parseColor("#FF6D00"), // dot 1
Color.parseColor("#FFD600"), // dot 2
Color.parseColor("#69F0AE"), // dot 3
Color.parseColor("#40C4FF"), // dot 4
)
// Optional: custom unselected colors per dot
dotsIndicator.dotColors = intArrayOf(
Color.parseColor("#FFCDD2"),
Color.parseColor("#FFE0B2"),
Color.parseColor("#FFF9C4"),
Color.parseColor("#CCFF90"),
Color.parseColor("#B3E5FC"),
)
Java-friendly setters are also available:
dotsIndicator.setSelectedDotColors(new int[]{Color.RED, Color.GREEN, Color.BLUE});
dotsIndicator.setDotColors(new int[]{Color.LTGRAY, Color.LTGRAY, Color.LTGRAY});

<com.tbuonomo.viewpagerdotsindicator.SpringDotsIndicator
android:id="@+id/spring_dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dampingRatio="0.5"
app:dotsColor="@color/material_white"
app:dotsStrokeColor="@color/material_yellow"
app:dotsCornerRadius="2dp"
app:dotsSize="16dp"
app:dotsSpacing="6dp"
app:dotsStrokeWidth="2dp"
app:stiffness="300"
app:dotsClickable="true" />
| Attribute | Description |
|---|---|
dotsColor | Color of the moving indicator dot |
dotsStrokeColor | Color of the stroke dots (defaults to the indicator color) |
dotsSize | Size of the dots (default: 16dp) |
dotsSpacing | Space between dots (default: 4dp) |
dotsCornerRadius | Dot corner radius (defaults to half of dotsSize) |
dotsStrokeWidth | Stroke width for the background dots (default: 2dp) |
dampingRatio | Spring force damping ratio (default: 0.5) |
stiffness | Spring force stiffness (default: 300) |
dotsClickable | Enables changing page when a dot is tapped (default: true) |
val springDotsIndicator = findViewById<SpringDotsIndicator>(R.id.spring_dots_indicator)
val viewPager = findViewById<ViewPager2>(R.id.view_pager)
viewPager.adapter = ViewPagerAdapter()
springDotsIndicator.attachTo(viewPager)

<com.tbuonomo.viewpagerdotsindicator.WormDotsIndicator
android:id="@+id/worm_dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dotsColor="@color/material_blueA200"
app:dotsStrokeColor="@color/material_yellow"
app:dotsCornerRadius="8dp"
app:dotsSize="16dp"
app:dotsSpacing="4dp"
app:dotsStrokeWidth="2dp"
app:dotsClickable="true" />
| Attribute | Description |
|---|---|
dotsColor | Color of the moving indicator dot |
dotsStrokeColor | Color of the stroke dots (defaults to the indicator color) |
dotsSize | Size of the dots (default: 16dp) |
dotsSpacing | Space between dots (default: 4dp) |
dotsCornerRadius | Dot corner radius (defaults to half of dotsSize) |
dotsStrokeWidth | Stroke width for the background dots (default: 2dp) |
dotsClickable | Enables changing page when a dot is tapped (default: true) |
val wormDotsIndicator = findViewById<WormDotsIndicator>(R.id.worm_dots_indicator)
val viewPager = findViewById<ViewPager2>(R.id.view_pager)
viewPager.adapter = ViewPagerAdapter()
wormDotsIndicator.attachTo(viewPager)
attachTo(...) accepts both androidx.viewpager.widget.ViewPager and androidx.viewpager2.widget.ViewPager2:
dotsIndicator.attachTo(viewPager)
dotsIndicator.attachTo(viewPager2)
If you could help me to continue maintain this repo, buying me a cup of coffee will make my life really happy and get much energy out of it.
setViewPager and setViewPager2 are now deprecated and replaced by attachTo(...)Fix #115
The library is now on MavenCentral.
The library name moves from com.tbuonomo.andrui:viewpagerdotsindicator to com.tbuonomo:dotsindicator
Fix crash
selectedDotColor and progressMode to DotsIndicatorDotsIndicator globallydotsStrokeColor to SpringDotsIndicator and WormDotsIndicatorCopyright 2016 Tommy Buonomo
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Overall
Maintained
Code review
Latest release
Releases this year
2,628 followers · starred Jun 2018
886 followers · starred Jan 2024
205 followers · starred Jun 2018
1,162 followers · starred Mar 2019
Dots indicators for Android ViewPager and Compose
Kotlin
3,604
240 commits
updated Oct 11, 2026
Dots Indicator is an Android library for Jetpack Compose and classic XML views 🚀
Compose support is built into the same artifact and exposes four indicator types: Shift, Spring, Worm, and Balloon.
Don't forget to star the project if you like it!
== 
Feel free to submit issues and enhancement requests!
Add Maven Central and the library dependency:
repositories {
google()
mavenCentral()
}
dependencies {
implementation("com.tbuonomo:dotsindicator:5.1.2")
}
DotsIndicator works directly with androidx.compose.foundation.pager.PagerState.
DotsIndicator(
dotCount = pageCount,
type = ShiftIndicatorType(
dotsGraphic = DotGraphic(color = MaterialTheme.colorScheme.primary)
),
pagerState = pagerState
)
DotsIndicator(
dotCount = pageCount,
type = SpringIndicatorType(
dotsGraphic = DotGraphic(
size = 16.dp,
borderWidth = 2.dp,
borderColor = MaterialTheme.colorScheme.primary,
color = Color.Transparent
),
selectorDotGraphic = DotGraphic(
size = 14.dp,
color = MaterialTheme.colorScheme.primary
)
),
pagerState = pagerState
)
DotsIndicator(
dotCount = pageCount,
type = WormIndicatorType(
dotsGraphic = DotGraphic(
size = 16.dp,
borderWidth = 2.dp,
borderColor = MaterialTheme.colorScheme.primary,
color = Color.Transparent,
),
wormDotGraphic = DotGraphic(
size = 16.dp,
color = MaterialTheme.colorScheme.primary,
)
),
pagerState = pagerState
)
DotsIndicator(
dotCount = pageCount,
type = BalloonIndicatorType(
dotsGraphic = DotGraphic(
size = 8.dp,
color = MaterialTheme.colorScheme.primary
),
balloonSizeFactor = 2f
),
dotSpacing = 20.dp,
pagerState = pagerState
)
Classic Android views are still supported for ViewPager and ViewPager2 with attachTo(...).

<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
android:id="@+id/dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dotsColor="@color/material_white"
app:dotsCornerRadius="8dp"
app:dotsElevation="4dp"
app:dotsSize="16dp"
app:dotsSpacing="4dp"
app:dotsWidthFactor="2.5"
app:selectedDotColor="@color/md_blue_200"
app:progressMode="true"
app:dotsClickable="true" />
| Attribute | Description |
|---|---|
dotsColor | Color of the dots |
selectedDotColor | Color of the selected dot (defaults to dotsColor) |
progressMode | Colors every previous dot with the selected dot color |
dotsSize | Size of the dots (default: 16dp) |
dotsSpacing | Space between dots (default: 8dp) |
dotsWidthFactor | Width multiplier for the selected dot (default: 2.5) |
dotsCornerRadius | Dot corner radius (defaults to half of dotsSize) |
dotsElevation | Elevation applied to the dots |
dotsClickable | Enables changing page when a dot is tapped (default: true) |
val dotsIndicator = findViewById<DotsIndicator>(R.id.dots_indicator)
val viewPager = findViewById<ViewPager2>(R.id.view_pager)
viewPager.adapter = ViewPagerAdapter()
dotsIndicator.attachTo(viewPager)
Give each dot its own selected and/or unselected color. Indices beyond the array length fall back to the global selectedDotColor / dotsColor. Empty arrays use the global colors, and assigning null restores them. Assigning an array refreshes existing dots; after changing an array element, reassign the array to repaint. In progressMode, passed dots retain their own selected color. This API applies only to the classic View-based DotsIndicator.
// Each dot lights up in a different accent color when selected
dotsIndicator.selectedDotColors = intArrayOf(
Color.parseColor("#FF5252"), // dot 0
Color.parseColor("#FF6D00"), // dot 1
Color.parseColor("#FFD600"), // dot 2
Color.parseColor("#69F0AE"), // dot 3
Color.parseColor("#40C4FF"), // dot 4
)
// Optional: custom unselected colors per dot
dotsIndicator.dotColors = intArrayOf(
Color.parseColor("#FFCDD2"),
Color.parseColor("#FFE0B2"),
Color.parseColor("#FFF9C4"),
Color.parseColor("#CCFF90"),
Color.parseColor("#B3E5FC"),
)
Java-friendly setters are also available:
dotsIndicator.setSelectedDotColors(new int[]{Color.RED, Color.GREEN, Color.BLUE});
dotsIndicator.setDotColors(new int[]{Color.LTGRAY, Color.LTGRAY, Color.LTGRAY});

<com.tbuonomo.viewpagerdotsindicator.SpringDotsIndicator
android:id="@+id/spring_dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dampingRatio="0.5"
app:dotsColor="@color/material_white"
app:dotsStrokeColor="@color/material_yellow"
app:dotsCornerRadius="2dp"
app:dotsSize="16dp"
app:dotsSpacing="6dp"
app:dotsStrokeWidth="2dp"
app:stiffness="300"
app:dotsClickable="true" />
| Attribute | Description |
|---|---|
dotsColor | Color of the moving indicator dot |
dotsStrokeColor | Color of the stroke dots (defaults to the indicator color) |
dotsSize | Size of the dots (default: 16dp) |
dotsSpacing | Space between dots (default: 4dp) |
dotsCornerRadius | Dot corner radius (defaults to half of dotsSize) |
dotsStrokeWidth | Stroke width for the background dots (default: 2dp) |
dampingRatio | Spring force damping ratio (default: 0.5) |
stiffness | Spring force stiffness (default: 300) |
dotsClickable | Enables changing page when a dot is tapped (default: true) |
val springDotsIndicator = findViewById<SpringDotsIndicator>(R.id.spring_dots_indicator)
val viewPager = findViewById<ViewPager2>(R.id.view_pager)
viewPager.adapter = ViewPagerAdapter()
springDotsIndicator.attachTo(viewPager)

<com.tbuonomo.viewpagerdotsindicator.WormDotsIndicator
android:id="@+id/worm_dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dotsColor="@color/material_blueA200"
app:dotsStrokeColor="@color/material_yellow"
app:dotsCornerRadius="8dp"
app:dotsSize="16dp"
app:dotsSpacing="4dp"
app:dotsStrokeWidth="2dp"
app:dotsClickable="true" />
| Attribute | Description |
|---|---|
dotsColor | Color of the moving indicator dot |
dotsStrokeColor | Color of the stroke dots (defaults to the indicator color) |
dotsSize | Size of the dots (default: 16dp) |
dotsSpacing | Space between dots (default: 4dp) |
dotsCornerRadius | Dot corner radius (defaults to half of dotsSize) |
dotsStrokeWidth | Stroke width for the background dots (default: 2dp) |
dotsClickable | Enables changing page when a dot is tapped (default: true) |
val wormDotsIndicator = findViewById<WormDotsIndicator>(R.id.worm_dots_indicator)
val viewPager = findViewById<ViewPager2>(R.id.view_pager)
viewPager.adapter = ViewPagerAdapter()
wormDotsIndicator.attachTo(viewPager)
attachTo(...) accepts both androidx.viewpager.widget.ViewPager and androidx.viewpager2.widget.ViewPager2:
dotsIndicator.attachTo(viewPager)
dotsIndicator.attachTo(viewPager2)
If you could help me to continue maintain this repo, buying me a cup of coffee will make my life really happy and get much energy out of it.
setViewPager and setViewPager2 are now deprecated and replaced by attachTo(...)Fix #115
The library is now on MavenCentral.
The library name moves from com.tbuonomo.andrui:viewpagerdotsindicator to com.tbuonomo:dotsindicator
Fix crash
selectedDotColor and progressMode to DotsIndicatorDotsIndicator globallydotsStrokeColor to SpringDotsIndicator and WormDotsIndicatorCopyright 2016 Tommy Buonomo
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Overall
Maintained
Code review
Latest release
Releases this year
2,628 followers · starred Jun 2018
886 followers · starred Jan 2024
205 followers · starred Jun 2018
1,162 followers · starred Mar 2019