How do you create an Android View Pager with a dots indicator?
Solution 1
All we need are: ViewPager, TabLayout and 2 drawables for selected and default dots.
Firstly, we have to add TabLayout
to our screen layout, and connect it with ViewPager
. We can do this in two ways:
Nested TabLayout
in ViewPager
<androidx.viewpager.widget.ViewPager
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.viewpager.widget.ViewPager>
In this case
TabLayout
will be automatically connected withViewPager
, butTabLayout
will be next toViewPager
, not over it.
Separate TabLayout
<androidx.viewpager.widget.ViewPager
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
In this case, we can put
TabLayout
anywhere, but we have to connectTabLayout
withViewPager
programmatically
ViewPager pager = (ViewPager) view.findViewById(R.id.photos_viewpager);
PagerAdapter adapter = new PhotosAdapter(getChildFragmentManager(), photosUrl);
pager.setAdapter(adapter);
TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(pager, true);
Once we created our layout, we have to prepare our dots. So we create three files: selected_dot.xml
, default_dot.xml
and tab_selector.xml
.
selected_dot.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@color/colorAccent"/>
</shape>
</item>
</layer-list>
default_dot.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@android:color/darker_gray"/>
</shape>
</item>
</layer-list>
tab_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/selected_dot"
android:state_selected="true"/>
<item android:drawable="@drawable/default_dot"/>
</selector>
Now we need to add only 3 lines of code to TabLayout
in our XML layout.
app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"
Solution 2
First Create a layout, in that give one LinerLayout for Dots which show over your View Pager
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:id="@+id/pager_dots"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:background="@android:color/transparent"
android:gravity="center_horizontal"
android:orientation="horizontal">
</LinearLayout>
</RelativeLayout>
After that create 2 drawables
1. Unselected Drawable
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent"/>
<size android:width="12dp" android:height="12dp"/>
<stroke android:width="1dp" android:color="#ffffff"/>
</shape>
2. Selected Drawable
<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent"/>
<size android:width="12dp" android:height="12dp"/>
<stroke android:width="1dp" android:color="#000000"/>
</shape>
After that set adapter
private LinearLayout llPagerDots;
private ViewPager viewPager;
private ArrayList<String> eventImagesUrl;
private HomeViewPagerAdapter homeViewPagerAdapter;
private ImageView[] ivArrayDotsPager;
public void setUpViewPager() {
viewPager = (ViewPager) findViewById(R.id.view_pager);
llPagerDots = (LinearLayout) findViewById(R.id.pager_dots);
homeViewPagerAdapter = new HomeViewPagerAdapter(mContext, eventImagesUrl);
viewPager.setAdapter(homeViewPagerAdapter);
setupPagerIndidcatorDots();
ivArrayDotsPager[0].setImageResource(R.drawable.page_indicator_selected);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
for (int i = 0; i < ivArrayDotsPager.length; i++) {
ivArrayDotsPager[i].setImageResource(R.drawable.page_indicator_unselected);
}
ivArrayDotsPager[position].setImageResource(R.drawable.page_indicator_selected);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
Create a method setupPagerIndidcatorDots() :
private void setupPagerIndidcatorDots() {
ivArrayDotsPager = new ImageView[eventImagesUrl.size()];
for (int i = 0; i < ivArrayDotsPager.length; i++) {
ivArrayDotsPager[i] = new ImageView(getActivity());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(5, 0, 5, 0);
ivArrayDotsPager[i].setLayoutParams(params);
ivArrayDotsPager[i].setImageResource(R.drawable.page_indicator_unselected);
//ivArrayDotsPager[i].setAlpha(0.4f);
ivArrayDotsPager[i].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
view.setAlpha(1);
}
});
llPagerDots.addView(ivArrayDotsPager[i]);
llPagerDots.bringToFront();
}
Solution 3
You can check out my library to handle your request : https://github.com/tommybuonomo/dotsindicator
In your XML layout
<com.tbuonomo.viewpagerdotsindicator.DotsIndicator
android:id="@+id/dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
app:dotsColor="@color/colorPrimary"
app:dotsSize="16dp"
app:dotsWidthFactor="3"
/>
In your Java code
dotsIndicator = (DotsIndicator) findViewById(R.id.dots_indicator);
viewPager = (ViewPager) findViewById(R.id.view_pager);
adapter = new ViewPagerAdapter();
viewPager.setAdapter(adapter);
dotsIndicator.setViewPager(viewPager);
Solution 4
When you want something similar to this with the latest ViewPager2 and Kotlin
Everything is self-explaining, no need to explain!
1. Your Activity or Fragment
val imageList = listOf(
ImageModel(R.drawable.offer1),
ImageModel(R.drawable.splash),
ImageModel(R.drawable.offer1),
ImageModel(R.drawable.splash2)
)
val adapter = HomeOffersAdapter()
adapter.setItem(imageList)
photos_viewpager.adapter = adapter
TabLayoutMediator(tab_layout, photos_viewpager) { tab, position ->
}.attach()
}
2. Layout
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_200">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_200" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|center"
app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"
app:tabSelectedTextColor="@android:color/transparent"
app:tabTextColor="@android:color/transparent" />
3. Drawable: tab_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dot_selected" android:state_selected="true" />
<item android:drawable="@drawable/dot_default" />
4. Drawable: dot_selected.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thickness="@dimen/dp_8"
android:useLevel="false">
<solid android:color="@color/colorPrimary" />
<stroke
android:width="@dimen/dp_1"
android:color="@android:color/white" />
5. Drawable: dot_default.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thickness="@dimen/dp_8"
android:useLevel="false">
<solid android:color="@android:color/transparent" />
<stroke
android:width="@dimen/dp_1"
android:color="@android:color/white" />
6. Adapter
class HomeOffersAdapter : RecyclerView.Adapter<HomeOffersAdapter.HomeOffersViewHolder>() {
private var list: List<ImageModel> = listOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOffersViewHolder {
return HomeOffersViewHolder(parent)
}
override fun onBindViewHolder(holder: HomeOffersViewHolder, position: Int) {
holder.bind(list[position])
}
fun setItem(list: List<ImageModel>) {
this.list = list
notifyDataSetChanged()
}
override fun getItemCount(): Int = list.size
class HomeOffersViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {
constructor(parent: ViewGroup) : this(
LayoutInflater.from(parent.context).inflate(
R.layout.pager_item,
parent, false
)
)
fun bind(imageModel: ImageModel) {
itemView.offerImage.setImageResource(imageModel.image)
}
}
}
7. Layout: pager_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/offerImage"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_200"
android:adjustViewBounds="true"
android:scaleType="fitXY"
tools:src="@drawable/offer1" />
Solution 5
2021, how to actually do it. ViewPager2 only.
Refer to this excellent short article, which has a couple of problems:
https://medium.com/@adrian.kuta93/android-viewpager-with-dots-indicator-a34c91e59e3a
Starting with a normal Android Studio default project as of 2021, with a reasonably new minimum (24 currently)...
General concept:
Make a standard TabLayout, but replace each "tab unit" with "a little dot" rather than the usual text.
In TabLayout, you can indeed replace each "tab unit" using "tabBackground":
app:tabBackground="@drawable/tab_selector"
So add the following to the XML of your screen, which has a ViewPager2:
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:background="#00FFFFFF"
app:tabBackground="@drawable/tab_selector"
app:tabIndicatorGravity="center"
app:tabIndicatorHeight="0dp"/>
Notice carefully we are replacing each and every one of the "tab units" in the TabLayout, with our own "tab_selector".
To be completely clear, "tabBackground" means the individual little "tab units", not the whole tab bar system.
(Aside, note that the two tricks tabIndicatorGravity and tabIndicatorHeight will indeed get rid of the "boxes" that are the usual "tab units".)
Next create three drawables in the obvious way, tab_selector and the two different dots. See the above article or 100s of examples on this page.
The magic code:
In your onCreate
have the expected code ...
viewPager = findViewById(R.id.simple_slide_pager);
tab_layout = findViewById(R.id.tab_layout);
viewPager.setAdapter(new ScreenSlidePagerAdapter(this));
and then here at last is the magic code fragment to make it work. Follow the above by:
Up to date for 2021:
TabLayoutMediator tabLayoutMediator =
new TabLayoutMediator(tab_layout, viewPager, true,
new TabLayoutMediator.TabConfigurationStrategy() {
@Override public void onConfigureTab(
@NonNull TabLayout.Tab tab, int position) { }
}
);
tabLayoutMediator.attach();
It's done.
(Inside onConfigureTab
you can do any sound effects or whatever the heck might be needed. For shorter syntax see the key comment by @F1iX above.)
Related videos on Youtube
RediOne1
Android enthusiast and professional developer since 2014.
Updated on April 12, 2022Comments
-
RediOne1 about 2 years
Probably many of you (as me), have problem with creating
ViewPager
with bottom dots, like this:How do you create such an Android ViewPager?
-
Fattie about 3 years2021 If you are pure ViewPager2 and 24+, the critical code for TabLayoutMediator has changed. I put in the latest in an answer below. What a PITA !
-
-
Erfan GLMPR over 7 yearsyou better put this in the documentation section. it helped though.
-
RediOne1 over 7 years@ErfanGholampour stackoverflow.com/documentation/android/692/viewpager/22945/…
-
Amit Singh almost 7 yearsHey, can you help me in reducing the gaps between the dots?
-
RediOne1 almost 7 years@AmitSingh You can use
app:tabMaxWidth
in TabLayout -
dawanse almost 7 yearscan't put those indicator in the bottom of layout overlapping
ViewPager
. When usingLinearLayout
it goes below theViewPager
and usingRelativeLayout
also same. -
RediOne1 almost 7 years@dawn
TabLayout
should be placed as separated widget (like in example SeparateTabLayout
. If you putTabLayout
as a child ofViewPager
it'll be autmoaticaly placed belowViewPager
and not overlap it. -
Seven over 6 yearsI do not know if I did not follow the instructions correctly but I also had to add the following in order to show only the dots with a decent space between them:
app:tabMaxWidth="30dp" app:tabTextColor="@color/transparent2" app:tabSelectedTextColor="@color/transparent2" app:tabIndicatorHeight="0dp" android:layout_gravity="bottom|center"
-
Fat Monk over 6 yearsI'm getting an error very like the one described in stackoverflow.com/questions/31712563/… when trying to use this. The solutions suggested for the linked question don;t resolve the problem either. The app compiles and runs OK ad there are no errors in the editor, but when the activity tries to inflate the app crashes.
-
Fat Monk over 6 yearsSo simple to use and looks great especially with the animations... thanks! I did, however, have to add
tools:replace="android:label"
to theapplication
tag in myAndroidManifest.xml
to get rid of an error about that tag being defined twice and causing a gradle build fail. -
Fat Monk over 6 yearsI am getting a
gradle
error, thoughError:(39, 20) All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes). Found versions 27.0.0, 25.3.1. Examples include 'com.android.support:support-compat:27.0.0' and 'com.android.support:animated-vector-drawable:25.3.1'
- how can i fix this? -
dev_mg99 over 6 yearsFor remove spacing between dots app:tabPaddingStart="@dimen/margin_7.5" app:tabPaddingEnd="@dimen/margin_7.5"
-
eC Droid over 6 yearsI have only Viewpager, please suggest what to do.
-
Sam almost 6 yearsI followed your answer and everything works really smoothly, thank you. I have one question though, in my app the
TabLayout
is always in the far top tried many things to put it in the bottom with no luck. I placed it nested in theViewPager
and also separately. still the same problem. Any ideas? -
Sam almost 6 yearsThank you I followed this link to fix the
TabLayout
position on the screen -
CoolMind almost 6 yearsProbably
SmartViewPager
is your custom view. -
CoolMind almost 6 yearsAfter adding
app:tabBackground="@drawable/tab_selector"
and others to TabLayout an application stopped compiling wih error. -
CoolMind almost 6 years@RediOne1, 3 lines of exception like
AGPBI: {"kind":"error","text":"error: attribute \u0027com.example:tabBackground\u0027 not found.","sources":[{"file":"C:\\Users\\user\\AndroidStudioProjects\\sample\\app\\src\\main\\res\\layout\\activity_start.xml","position":{"startLine":53}}],"original":"","tool":"AAPT"}
. After removingapp
attributes it crushes with exceptionCaused by: android.view.InflateException: Binary XML file line #54: Error inflating class android.support.design.widget.TabLayout
. I write in Kotlin. -
CoolMind almost 6 yearsAnd what is
HomeViewPagerAdapter
? -
RediOne1 almost 6 years@CoolMind Do you have
xmlns:app="http://schemas.android.com/apk/res-auto"
on top of your layout file? If you can, please paste whole layout file to pastebin.com and paste link here. -
CoolMind almost 6 years@RediOne1, yes, i have this attribute. I removed
TabLayout
, because it is not needed. But if you wish, I can create a sample layout for you. -
RediOne1 almost 6 years@CoolMind Ok, do it, please.
-
amity over 5 yearsModify onPageSelect little to work perfectly as below override fun onPageSelected(position: Int) { for (i in 0 until ivArrayDotsPager!!.size) { if (i != position) ivArrayDotsPager!![i].setImageDrawable(ContextCompat.getDrawable(applicationContext, R.drawable.unselected_dot)) else ivArrayDotsPager!![i].setImageDrawable(ContextCompat.getDrawable(applicationContext, R.drawable.selected_dot)) } linearLayout!!.bringToFront()}
-
Touré Holder over 5 years@RediOne1 The xml could just be a <shape>, instead of a <shape> in an <item> in a <layer-list>, right?
-
RediOne1 over 5 years@Touré Holder Yes
-
Shivam Kumar over 5 yearshow to scroll automatically DotsIndicator
-
Black_Zerg about 5 yearsThanks! Just need place TabLayout outside ViewPager to place below ViewPager
-
Maveňツ about 5 yearsunable to find tabIndicatorHeight
-
Jordan H about 5 yearsI had to add
implementation 'com.android.support:support-v4:x.x.x'
into the dependencies, otherwise I got errors likeAndroid resource linking failed
attribute tabBackground (aka com.company.appname:tabBackground) not found.
-
Aniket over 4 years<com.google.android.material.tabs.TabLayout use this in androidx
-
Admin over 4 yearshey ..I implemented this..I used <com.tbuonomo.viewpagerdotsindicator.WormDotsIndicator> but dots are getting displayed at extreme left ..how to align dots at centre?
-
IgorGanapolsky about 4 yearsHow to do this with
ViewPager2
andTabLayoutMediator
? -
RediOne1 about 4 years@IgorGanapolsky I prepared simple demo for ViewPager and ViewPager2: github.com/AdrianKuta/ViewPagerDotsIndicator I will also update Answer, thank you for this question ;-)
-
Hari Kiran almost 4 yearsshould a separate tablayout be created if I want to display dots below viewpager?
-
Sai almost 4 yearsAnd finally, to disable tab touch events use this
tab_layout.touchables?.forEach { it.isEnabled = false }
-
Sai almost 4 yearsTo play with the space/gap between tabs and to remove indication use this
app:tabPaddingStart="8dp" app:tabPaddingEnd="8dp" app:tabIndicatorHeight="0dp"
-
meekash55 over 3 yearsnice ,but this uses AndroidX. I am in situation that i cannot migrate my project into AndroidX now.
-
F1iX over 3 yearsFor ViewPager2 with Java, you need
viewPager = findViewById(R.id.pager);pagerAdapter = new ScreenSlidePagerAdapter(this); viewPager.setAdapter(pagerAdapter); tabLayout = findViewById(R.id.tabs); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {}).attach();
-
Fattie about 3 yearsbravo @F1iX exactly
-
Tri Mueri Sandes about 3 years@meekash55 I prefer you migrate to android X at the beginning build App, cause there many cases that make you should move to Android X, this case is one of the samples.
-
Tri Mueri Sandes about 3 yearsI think to migrate not took too long, but this is your decision. adjust to your situation and conditions
-
Bungles over 2 yearsThis was a great help, thanks. When I set <android:thickness="16dp"> in the two DOT.XML files, I'd expect the dot bar to adjust size accordingly - but it does not. I need them bigger for our audience, so was hoping you could direct me where to make that change so they're larger on screen?
-
Fattie over 2 yearshell that's a tough one, I'm rusty. i think you have to actually make the thing that holds it (the tab_selector ?) BIGGER. that determines the size? I am sorry ... it s a good question, ask a new question about it !