Android
ViewPager
BottomNavigation
UI Components
Mobile Development

Android ViewPager with bottom dots

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A ViewPager with bottom dots is a common onboarding pattern in Android apps. The implementation seems simple, but good behavior depends on page state sync, lifecycle safety, and clear visual feedback. A robust setup works across rotations and dynamic page counts without visual glitches.

A robust approach should remain reliable under maintenance, deployment, and troubleshooting pressure. Clear assumptions and repeatable validation steps are as important as the initial fix.

Core Sections

1. Set up pager and indicator model

Start by defining a single source of truth for current page index and total page count. Whether you use classic ViewPager, ViewPager2, or Compose pager APIs, indicator state should be derived from pager state, not duplicated in multiple listeners.

kotlin
1val adapter = OnboardingAdapter(pages)
2viewPager.adapter = adapter
3
4val indicator = findViewById<LinearLayout>(R.id.dotContainer)
5fun renderDots(current: Int, total: Int) {
6    indicator.removeAllViews()
7    repeat(total) { idx ->
8        val dot = View(this).apply {
9            layoutParams = LinearLayout.LayoutParams(16, 16).also { lp ->
10                lp.marginEnd = 8
11            }
12            background = ContextCompat.getDrawable(
13                this@MainActivity,
14                if (idx == current) R.drawable.dot_active else R.drawable.dot_inactive
15            )
16        }
17        indicator.addView(dot)
18    }
19}
20renderDots(0, adapter.itemCount)

Start with a minimal implementation and validate one expected success path before adding complexity. This gives a stable baseline for later hardening.

2. Sync dots with pager callbacks

Register page change callbacks once in lifecycle-aware scope. Update indicator only from callback events to avoid stale UI during quick swipes or programmatic page changes.

kotlin
1viewPager.registerOnPageChangeCallback(
2    object : ViewPager2.OnPageChangeCallback() {
3        override fun onPageSelected(position: Int) {
4            renderDots(position, adapter.itemCount)
5        }
6    }
7)
8
9nextButton.setOnClickListener {
10    val next = (viewPager.currentItem + 1).coerceAtMost(adapter.itemCount - 1)
11    viewPager.currentItem = next
12}

Once baseline behavior is correct, harden around edge conditions and explicit error handling. This stage usually determines production reliability.

3. Handle accessibility and configuration changes

Indicators should be readable with screen readers and resilient across recreation. Persist current page in saved state and expose meaningful accessibility descriptions for active and inactive dots.

Include one edge-case and one failure-path check in automation so regressions are caught early. Operational readiness should also include focused telemetry and rollback planning before release.

Document ownership and runbook steps near the code path so on-call responders can reproduce and mitigate issues quickly under pressure.

Implementation quality also depends on operational clarity. Define expected inputs, boundary conditions, and explicit failure semantics so callers know what to do when results are unavailable or partially successful. Without this contract, different parts of the system often apply inconsistent assumptions, which creates subtle defects that are expensive to diagnose during incident response.

Automated validation should include one representative production-like scenario, one malformed-input case, and one dependency-failure case. Keep these tests deterministic and fast so they run on every change. Repeated CI execution is the most effective way to catch regressions introduced by refactoring, dependency upgrades, or environment changes that are not obvious from local ad hoc testing.

Observability is part of the design, not an afterthought. Log key branch decisions with concise context, include correlation identifiers where available, and track metrics tied directly to user impact such as latency percentiles and error categories. Focused telemetry helps responders distinguish code defects from infrastructure issues quickly and keeps troubleshooting time bounded.

Before release, prepare rollback and fallback behavior explicitly. Feature toggles, staged rollout, and clear reversion procedures reduce risk when assumptions fail under real traffic. Teams that plan recovery in advance can ship improvements more confidently and restore service faster when unexpected conditions occur.

Capture post-release metrics against baseline values and record findings so future changes can build on measured evidence rather than assumptions.

Common Pitfalls

  • Updating dot state from multiple unsynchronized listeners and creating flicker.
  • Hardcoding dot count instead of deriving it from adapter item count.
  • Forgetting state restoration after rotation and resetting to first page unexpectedly.
  • Using too-small dot sizes that fail accessibility touch target guidance.
  • Neglecting content descriptions, making indicators opaque to assistive tools.

Summary

  • Derive indicator state from one pager source of truth.
  • Update dots in page selection callbacks only.
  • Persist current page and test rotation behavior.
  • Include accessibility metadata for each indicator state.

Course illustration
Course illustration

All Rights Reserved.