Android ViewPager z dolnymi kropkami

Odpowiedzi:

356

Nie potrzeba tak dużo kodu.

Możesz robić wszystkie te rzeczy bez kodowania, używając tylko viewpagerz tablayout.

Twój główny układ:

<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="wrap_content">

   <android.support.v4.view.ViewPager
       android:id="@+id/pager"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

   </android.support.v4.view.ViewPager>
   <android.support.design.widget.TabLayout
       android:id="@+id/tabDots"
       android:layout_alignParentBottom="true"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:tabBackground="@drawable/tab_selector"
       app:tabGravity="center"
       app:tabIndicatorHeight="0dp"/>
</RelativeLayout>

Podłącz nieaktywność lub fragment elementów interfejsu użytkownika w następujący sposób:

Kod Java:

mImageViewPager = (ViewPager) findViewById(R.id.pager);
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabDots);
tabLayout.setupWithViewPager(mImageViewPager, true);

To wszystko, dobrze jest iść.

Będziesz musiał utworzyć następujący plik zasobów xml w folderze, który można wyciągnąć .

tab_indicator_selected.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    android:innerRadius="0dp"
    android:shape="oval"
    android:thickness="4dp"
    android:useLevel="false"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@color/colorAccent"/>
</shape>

tab_indicator_default.xml

<?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
            android:innerRadius="0dp"
            android:shape="oval"
            android:thickness="2dp"
            android:useLevel="false">
            <solid android:color="@android:color/darker_gray"/>
    </shape>

tab_selector.xml

 <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/tab_indicator_selected"
          android:state_selected="true"/>

    <item android:drawable="@drawable/tab_indicator_default"/>
</selector>

Czujesz się tak leniwy jak ja? Cały powyższy kod jest konwertowany na bibliotekę! Sposób użycia Dodaj do swojej oceny: implementation 'com.chabbal:slidingdotsplash:1.0.2' Dodaj następujące elementy do układu działania lub fragmentu.

<com.chabbal.slidingdotsplash.SlidingSplashView
        android:id="@+id/splash"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:imageResources="@array/img_id_arr"/>

Utwórz tablicę liczb całkowitych strings.xmlnp

<integer-array name="img_id_arr">
   <item>@drawable/img1</item>
   <item>@drawable/img2</item>
   <item>@drawable/img3</item>
   <item>@drawable/img4</item>
</integer-array>

Gotowe! Dodatkowo w celu odsłuchania zmian na stronie użyj linkuaddOnPageChangeListener(listener); Github .

Junaid
źródło
3
Już głosowałem, zanim zadałem pytanie, ponieważ już mi to bardzo pomogło, ale teraz chciałbym móc wyróżnić +2 lub +100 :), ponieważ dodanie onPageChangeListener działało dla mnie idealnie! I aby było to jasne dla każdego, kto może z tego skorzystać, musisz robić aktualizacje tylko na wywołaniu zwrotnym onPageSelected, dodanie aktualizacji w wywołaniu zwrotnym onPageScrolled powoduje bałagan, uruchamia aktualizację natychmiast po rozpoczęciu przewijania, co nie jest wizualnie dobry!
Mohamed Hamdaoui
1
Dlaczego potrzebujemy TabLayout?
winklerrr
14
Chcesz używać com.google.android.material.tabs.TabLayoutw nowszych wersjach
schlenger
2
Aktualizacja: to działa, ale powinieneś używać nowych komponentów: androidx.viewpager.widget.ViewPager i com.google.android.material.tabs.TabLayout
dreinoso 24.09.19
2
Powyższy rysunkowy XML wygląda dziwnie, dopóki nie zmieniłem kształtu na ring. Wygląda na to, że pierścień jest również używany w bibliotece slidedotsplash zamiast owalu.
katie
39

Moje ręcznie wykonane rozwiązanie:

W układzie:

<LinearLayout
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/dots"
        />

I w działaniu

private final static int NUM_PAGES = 5;
private ViewPager mViewPager;
private List<ImageView> dots;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // ...
    addDots();
}

public void addDots() {
    dots = new ArrayList<>();
    LinearLayout dotsLayout = (LinearLayout)findViewById(R.id.dots);

    for(int i = 0; i < NUM_PAGES; i++) {
        ImageView dot = new ImageView(this);
        dot.setImageDrawable(getResources().getDrawable(R.drawable.pager_dot_not_selected));

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
        );
        dotsLayout.addView(dot, params);

        dots.add(dot);
    }

    mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }

        @Override
        public void onPageSelected(int position) {
            selectDot(position);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
        }
    });
}

public void selectDot(int idx) {
    Resources res = getResources();
    for(int i = 0; i < NUM_PAGES; i++) {
        int drawableId = (i==idx)?(R.drawable.pager_dot_selected):(R.drawable.pager_dot_not_selected);
        Drawable drawable = res.getDrawable(drawableId);
        dots.get(i).setImageDrawable(drawable);
    }
}
Marin Shalamanov
źródło
3
Po co używać ciężkiego komponentu Layouttylko do kropki? Użyj Viewzamiast tego.
Apurva,
2
Myślę, że układ liniowy jest taki, że wyśrodkuje i zgrupuje kropki.
ShawnV
38
viewPager.addOnPageChangeListener(new OnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {

                switch (position) {
    case 0:
        img_page1.setImageResource(R.drawable.dot_selected);
        img_page2.setImageResource(R.drawable.dot);
        img_page3.setImageResource(R.drawable.dot);
        img_page4.setImageResource(R.drawable.dot);
        break;

    case 1:
        img_page1.setImageResource(R.drawable.dot);
        img_page2.setImageResource(R.drawable.dot_selected);
        img_page3.setImageResource(R.drawable.dot);
        img_page4.setImageResource(R.drawable.dot);
        break;

    case 2:
        img_page1.setImageResource(R.drawable.dot);
        img_page2.setImageResource(R.drawable.dot);
        img_page3.setImageResource(R.drawable.dot_selected);
        img_page4.setImageResource(R.drawable.dot);
        break;

    case 3:
        img_page1.setImageResource(R.drawable.dot);
        img_page2.setImageResource(R.drawable.dot);
        img_page3.setImageResource(R.drawable.dot);
        img_page4.setImageResource(R.drawable.dot_selected);
        break;

    default:
        break;
    }


            }

            @Override
            public void onPageScrolled(int arg0, float arg1, int arg2) {

            }

            @Override
            public void onPageScrollStateChanged(int arg0) {

            }
        });
kapil thadani
źródło
18
setOnPageChangedListener()przestarzałe !! Użyj addOnPageChangedListener()teraz.
Apurva
12
To nie jest naprawdę świetne rozwiązanie, ponieważ musisz dokładnie wiedzieć, ile stron będziesz używać. Gdy tylko dodasz lub usuniesz stronę, masz kłopoty.
FrostRocket 27.07.16
3
Nie walcz z ramami. Android ma narzędzia do robienia tego jako TabLayout, nie ma powodu, aby wymyślać koło na nowo.
kike
3
Uprość to: private void setDotSelection (int index) {dot1.setImageResource (index == 0? R.drawable.circle_selected: R.drawable.circle); dot2.setImageResource (index == 1? R.drawable.circle_selected: R.drawable.circle); dot3.setImageResource (index == 2? R.drawable.circle_selected: R.drawable.circle); dot4.setImageResource (index == 3? R.drawable.circle_selected: R.drawable.circle); dot5.setImageResource (index == 4? R.drawable.circle_selected: R.drawable.circle); }
Duna,
31

Utworzyłem bibliotekę, aby zaspokoić potrzebę wskaźnika strony w ViewPager. Moja biblioteka zawiera widok o nazwie DotIndicator. Aby skorzystać z mojej biblioteki, dodaj compile 'com.matthew-tamlin:sliding-intro-screen:3.2.0'do pliku kompilacji stopni.

Widok można dodać do układu, dodając następujące elementy:

    <com.matthewtamlin.sliding_intro_screen_library.indicators.DotIndicator
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:numberOfDots=YOUR_INT_HERE
            app:selectedDotIndex=YOUR_INT_HERE/>

Powyższy kod doskonale odwzorowuje funkcjonalność kropek na ekranie głównym Launchera Google, jednak jeśli chcesz go dalej dostosować, możesz dodać następujące atrybuty:

  • app:unselectedDotDiameteri app:selectedDotDiameteraby ustawić średnice kropek
  • app:unselectedDotColori app:selectedDotColoraby ustawić kolory kropek
  • app:spacingBetweenDots aby zmienić odległość między kropkami
  • app:dotTransitionDuration ustawić czas animacji zmiany z małej na dużą (iz powrotem)

Ponadto widok można utworzyć programowo za pomocą:

DotIndicator indicator = new DotIndicator(context);

Istnieją metody modyfikowania właściwości, podobne do atrybutów. Aby zaktualizować wskaźnik, aby wyświetlał inną wybraną stronę, wystarczy wywołać metodę indicator.setSelectedItem(int, true)od wewnątrz ViewPager.OnPageChangeListener.onPageSelected(int).

Oto przykład użycia:

wprowadź opis zdjęcia tutaj

Jeśli jesteś zainteresowany, biblioteka została zaprojektowana do tworzenia ekranów wprowadzających, takich jak pokazane w powyższym gifie.

Źródło Github dostępne tutaj: https://github.com/MatthewTamlin/SlidingIntroScreen

Helios
źródło
Wystąpił błąd w indicator.setSelectedItem (position, true); IndexOutOfBoundsException
Dixit Panchal
Która wersja Myślałem, że naprawiłem to w 3.0.1, jakie były twoje wartości dla wskaźnika.size () i pozycji?
Helios,
Świetna biblioteka! Czy jest jednak bardziej elegancki sposób na jednoczesne aktualizowanie selectedItem i numberOfItems? W zależności od tego, który jest większy, kolejność zmienia się, w przeciwnym razie zgłaszasz wyjątek IndexOutOfBounds. Zobacz tę treść .
vsp
@vsp DotIndicator implementuje interfejs SelectionIndicator, co oznacza, że ​​ma dwie przydatne metody, które mogą rozwiązać Twój problem: int getNumberOfItems()i void setNumberOfItems(). Zamiast wyłapać wyjątek, możesz zrobić coś takiego: gist.github.com/MatthewTamlin/761c7338d271af29526edc7859480aef .
Helios,
Dla każdego, kto nie podąża za rozmową, rzeczywiście został naprawiony błąd. 3.0.2 to najnowsza wersja od teraz.
Helios,
18

ViewPagerIndicator nie był aktualizowany od 2012 roku i otrzymał kilka błędów, które nigdy nie zostały naprawione.

W końcu znalazłem alternatywę dla tej biblioteki światła, która wyświetla ładne kropki viewpager, oto link:

https://github.com/ongakuer/CircleIndicator

Łatwy do wdrożenia!

Yoann Hercouet
źródło
16

Pomyślałem o opublikowaniu prostszego rozwiązania powyższego problemu, a numery wskaźników można dynamicznie zmieniać za pomocą tylko jednej zmiennej, dotCounts=xco zrobiłem, tak to wygląda.

1) Utwórz plik xml w folderze do rysowania dla wybranego wskaźnika strony o nazwie „item_selected”.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" android:useLevel="true"
    android:dither="true">
    <size android:height="8dp" android:width="8dp"/>
    <solid android:color="@color/image_item_selected_for_dots"/>
</shape>

2) Utwórz jeszcze jeden plik xml dla niezaznaczonego wskaźnika o nazwie „item_unselected”

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" android:useLevel="true"
    android:dither="true">

    <size android:height="8dp" android:width="8dp"/>

    <solid android:color="@color/image_item_unselected_for_dots"/>
</shape>

3) Teraz dodaj dodaj tę część kodu w miejscu, w którym chcesz wyświetlić wskaźniki ex np viewPager. W pliku XML układu.

 <RelativeLayout
        android:id="@+id/viewPagerIndicator"
        android:layout_width="match_parent"
        android:layout_below="@+id/banner_pager"
        android:layout_height="wrap_content"
        android:gravity="center">

        <LinearLayout
            android:id="@+id/viewPagerCountDots"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:orientation="horizontal" />
        </RelativeLayout>

4) Dodaj tę funkcję na górze pliku pliku aktywności, w którym układ jest zawyżony lub z którym związany jest powyższy plik xml

private int dotsCount=5;    //No of tabs or images
private ImageView[] dots;
LinearLayout linearLayout;

private void drawPageSelectionIndicators(int mPosition){
    if(linearLayout!=null) {
        linearLayout.removeAllViews();
    }
    linearLayout=(LinearLayout)findViewById(R.id.viewPagerCountDots);
    dots = new ImageView[dotsCount];
    for (int i = 0; i < dotsCount; i++) {
        dots[i] = new ImageView(context);
        if(i==mPosition)
            dots[i].setImageDrawable(getResources().getDrawable(R.drawable.item_selected));
        else
            dots[i].setImageDrawable(getResources().getDrawable(R.drawable.item_unselected));

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
        );

        params.setMargins(4, 0, 4, 0);
        linearLayout.addView(dots[i], params);
    }
}

5) Na koniec w metodzie onCreate dodaj następujący kod, aby odwoływać się do układu i obsługiwać pozycje wybrane na stronie

drawPageSelectionIndicators(0);
mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
        drawPageSelectionIndicators(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
    }
});
Lokanath
źródło
13

Możesz wypróbować bibliotekę Jake'a Whartona - https://github.com/JakeWharton/Android-ViewPagerIndicator

Joel Fernandes
źródło
Jak mogę dodawać kropki, a nie zakładki (takie jak program uruchamiający Nexusa 5)?
Kfir Guy
@KfirGuy Są one nazywane wskaźnikami. Możesz to zrobić za pomocą biblioteki, o której wspomniałem powyżej. Możesz to zobaczyć tutaj w akcji - play.google.com/store/apps/…
Joel Fernandes
@JoelFernandes wygląda na to, że ta aplikacja nie jest dostępna we wszystkich krajach
34m0
9

Oto moje proponowane rozwiązanie.

  • Ponieważ musimy wyświetlać tylko niektóre obrazy w pagerach widoku, uniknęliśmy uciążliwego korzystania z fragmentów.
    • Wdrożono wskaźniki strony widoku (dolne kropki bez dodatkowej biblioteki lub wtyczki)
    • Po dotknięciu wskaźników strony widoku (kropek) odbywa się również nawigacja strony.
    • Nie zapomnij dodać własnych zdjęć do zasobów.
    • Skomentuj i popraw to.

A) Poniżej znajduje się moja aktywność

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="schneider.carouseladventure.MainActivity">

    <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/viewpager"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <RelativeLayout
        android:id="@+id/viewPagerIndicator"
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:layout_alignParentBottom="true"
        android:layout_marginTop="5dp"
        android:gravity="center">

        <LinearLayout
            android:id="@+id/viewPagerCountDots"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:orientation="horizontal" />

    </RelativeLayout>


</RelativeLayout>

B) pager_item.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/imageView" />
</LinearLayout>

C) MainActivity.java

import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener, View.OnClickListener {

    int[] mResources = {R.drawable.nature1, R.drawable.nature2, R.drawable.nature3, R.drawable.nature4,
            R.drawable.nature5, R.drawable.nature6
    };

    ViewPager mViewPager;
    private CustomPagerAdapter mAdapter;
    private LinearLayout pager_indicator;
    private int dotsCount;
    private ImageView[] dots;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mViewPager = (ViewPager) findViewById(R.id.viewpager);
        pager_indicator = (LinearLayout) findViewById(R.id.viewPagerCountDots);
        mAdapter = new CustomPagerAdapter(this, mResources);
        mViewPager.setAdapter(mAdapter);
        mViewPager.setCurrentItem(0);
        mViewPager.setOnPageChangeListener(this);

        setPageViewIndicator();

    }

    private void setPageViewIndicator() {

        Log.d("###setPageViewIndicator", " : called");
        dotsCount = mAdapter.getCount();
        dots = new ImageView[dotsCount];

        for (int i = 0; i < dotsCount; i++) {
            dots[i] = new ImageView(this);
            dots[i].setImageDrawable(getResources().getDrawable(R.drawable.nonselecteditem_dot));

            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
            );

            params.setMargins(4, 0, 4, 0);

            final int presentPosition = i;
            dots[presentPosition].setOnTouchListener(new View.OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    mViewPager.setCurrentItem(presentPosition);
                    return true;
                }

            });


            pager_indicator.addView(dots[i], params);
        }

        dots[0].setImageDrawable(getResources().getDrawable(R.drawable.selecteditem_dot));
    }

    @Override
    public void onClick(View v) {

    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

    }

    @Override
    public void onPageSelected(int position) {

        Log.d("###onPageSelected, pos ", String.valueOf(position));
        for (int i = 0; i < dotsCount; i++) {
            dots[i].setImageDrawable(getResources().getDrawable(R.drawable.nonselecteditem_dot));
        }

        dots[position].setImageDrawable(getResources().getDrawable(R.drawable.selecteditem_dot));

        if (position + 1 == dotsCount) {

        } else {

        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {

    }
}

D) CustomPagerAdapter.java

 import android.content.Context;
    import android.support.v4.view.PagerAdapter;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.LinearLayout;

    public class CustomPagerAdapter extends PagerAdapter {
        private Context mContext;
        LayoutInflater mLayoutInflater;
        private int[] mResources;

        public CustomPagerAdapter(Context context, int[] resources) {
            mContext = context;
            mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            mResources = resources;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {

            View itemView = mLayoutInflater.inflate(R.layout.pager_item,container,false);
            ImageView imageView = (ImageView) itemView.findViewById(R.id.imageView);
            imageView.setImageResource(mResources[position]);
           /* LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(950, 950);
            imageView.setLayoutParams(layoutParams);*/
            container.addView(itemView);
            return itemView;
        }

        @Override
        public void destroyItem(ViewGroup collection, int position, Object view) {
            collection.removeView((View) view);
        }

        @Override
        public int getCount() {
            return mResources.length;
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }
    }

E) selecteditem_dot.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" android:useLevel="true"
    android:dither="true">

    <size android:height="12dip" android:width="12dip"/>

    <solid android:color="#7e7e7e"/>
</shape>

F) nonselecteditem_dot.xml

 <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval" android:useLevel="true"
        android:dither="true">        
        <size android:height="12dip" android:width="12dip"/>        
        <solid android:color="#d3d3d3"/>
    </shape>

pierwszy obraz

wprowadź opis zdjęcia tutaj

Ajit
źródło
użyłem tego, ale w przeglądarce nie zmieniają się punkty przewijania
Aditya Vyas-Lakhan,
1
to najlepsza odpowiedź.
Sandeep Londhe
1

Jeśli ktoś chce budować viewPagerz miniaturami jako wskaźnikami, skorzystanie z tej biblioteki może być opcją: ThumbIndicator dla viewPager, który działa również z łączami obrazów jako zasobami.

Mahdi Moqadasi
źródło
0

Oto jak to zrobiłem, nieco podobne do powyższych rozwiązań. Tylko upewnij się nazywają () loadDots metoda po wszystkie obrazy zostaną pobrane .

    private int dotsCount;
    private TextView dotsTextView[];

    private void setupAdapter() {
        adapter = new SomeAdapter(getContext(), images);
        viewPager.setAdapter(adapter);
        viewPager.setCurrentItem(0);
        viewPager.addOnPageChangeListener(viewPagerPageChangeListener);
    }

    private final ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

        @Override
        public void onPageSelected(int position) {
            for (int i = 0; i < dotsCount; i++)
                dotsTextView[i].setTextColor(Color.GRAY);

            dotsTextView[position].setTextColor(Color.WHITE);
        }

        @Override
        public void onPageScrollStateChanged(int state) {}
    };

    protected void loadDots() {
        dotsCount = adapter.getCount();
        dotsTextView = new TextView[dotsCount];
        for (int i = 0; i < dotsCount; i++) {
            dotsTextView[i] = new TextView(getContext());
            dotsTextView[i].setText(R.string.dot);
            dotsTextView[i].setTextSize(45);
            dotsTextView[i].setTypeface(null, Typeface.BOLD);
            dotsTextView[i].setTextColor(android.graphics.Color.GRAY);
            mDotsLayout.addView(dotsTextView[i]);
        }
        dotsTextView[0].setTextColor(Color.WHITE);
    }

XML

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:background="#00000000"/>


    <ImageView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/introImageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <LinearLayout
        android:id="@+id/image_count"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00000000"
        android:gravity="center|bottom"
        android:orientation="horizontal"/>
</FrameLayout>
r3dm4n
źródło