Android ViewPager con puntos inferiores

Respuestas:

356

No hay necesidad de tanto código.

Puedes hacer todo esto sin codificar demasiado si solo lo usas viewpagercon tablayout.

Su diseño principal:

<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>

Conecte los elementos de la IU inactividad o fragmento de la siguiente manera:

Código Java:

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

Eso es todo, eres bueno para ir.

Deberá crear el siguiente archivo de recursos xml en la carpeta dibujable .

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>

¿Te sientes tan vago como yo? Bueno, ¡todo el código anterior se convierte en una biblioteca! Uso Agregue lo siguiente en su gradle: implementation 'com.chabbal:slidingdotsplash:1.0.2' Agregue lo siguiente a su diseño de Actividad o Fragmento.

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

Crear una matriz de enteros en, strings.xmlpor ejemplo,

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

¡Hecho! Adicional para escuchar los cambios de página, use el enlace deaddOnPageChangeListener(listener); Github .

Junaid
fuente
3
Ya había votado antes de hacer la pregunta, porque ya me ayudó mucho, pero ahora desearía poder votar +2 o +100 :) porque agregar onPageChangeListener funcionó perfectamente para mí. Y solo para dejar en claro a cualquiera que pueda usar esto, debe hacer sus actualizaciones solo en la devolución de llamada onPageSelected, agregar la actualización en la devolución de llamada onPageScrolled lo hace desordenado, comienza la actualización tan pronto como comienza a desplazarse, lo que no es visualmente bueno!
Mohamed Hamdaoui
1
¿Por qué necesitamos un TabLayout?
winklerrr
14
Desea usar com.google.android.material.tabs.TabLayouten versiones más recientes
schlenger
2
Actualización: eso funciona pero debe usar nuevos componentes: androidx.viewpager.widget.ViewPager y com.google.android.material.tabs.TabLayout
dreinoso
2
El XML dibujable anterior se ve raro hasta que cambié de forma ring. Parece que el anillo también se usa en la biblioteca slidedotsplash en lugar de ovalado.
Katie
39

Mi solución hecha a mano:

En el diseño:

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

Y en la actividad

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
fuente
3
¿Por qué usar componentes pesados Layoutsolo para poner un punto? Usar en su Viewlugar.
Apurva
2
Creo que el diseño lineal es para centrar y agrupar los puntos.
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
fuente
18
setOnPageChangedListener()¡¡obsoleto!! Úselo addOnPageChangedListener()ahora.
Apurva el
12
Esta no es realmente una gran solución, ya que debes saber exactamente cuántas páginas usarás. Tan pronto como agregue o elimine una página, tendrá problemas.
FrostRocket
3
No luches contra el marco. Android tiene herramientas para hacer esto como TabLayout, no hay razón para reinventar la rueda.
kike
3
Simplifique a esto: 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

Creé una biblioteca para abordar la necesidad de un indicador de página en un ViewPager. Mi biblioteca contiene una vista llamada DotIndicator. Para usar mi biblioteca, agréguelo compile 'com.matthew-tamlin:sliding-intro-screen:3.2.0'a su archivo de compilación de gradle.

La Vista se puede agregar a su diseño agregando lo siguiente:

    <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/>

El código anterior reproduce perfectamente la funcionalidad de los puntos en la pantalla de inicio de Google Launcher, sin embargo, si desea personalizarlo aún más, se pueden agregar los siguientes atributos:

  • app:unselectedDotDiametery app:selectedDotDiameterpara establecer los diámetros de los puntos
  • app:unselectedDotColory app:selectedDotColorpara establecer los colores de los puntos
  • app:spacingBetweenDots para cambiar la distancia entre los puntos
  • app:dotTransitionDuration para establecer el tiempo para animar el cambio de pequeño a grande (y viceversa)

Además, la vista se puede crear mediante programación mediante:

DotIndicator indicator = new DotIndicator(context);

Existen métodos para modificar las propiedades, similares a los atributos. Para actualizar el indicador para mostrar una página diferente según lo seleccionado, simplemente llame al método indicator.setSelectedItem(int, true)desde adentro ViewPager.OnPageChangeListener.onPageSelected(int).

Aquí hay un ejemplo de ello en uso:

ingrese la descripción de la imagen aquí

Si está interesado, la biblioteca en realidad fue diseñada para hacer pantallas de introducción como la que se muestra en el gif anterior.

Fuente de Github disponible aquí: https://github.com/MatthewTamlin/SlidingIntroScreen

Helios
fuente
Error obtenido en indicator.setSelectedItem (posición, verdadero); IndexOutOfBoundsException
Dixit Panchal
¿Cual version? Pensé que solucioné eso en 3.0.1, ¿también cuáles eran sus valores para indicator.size () y position?
Helios
Gran biblioteca! Sin embargo, ¿hay una forma más elegante de actualizar selectedItem y numberOfItems al mismo tiempo? Dependiendo de cuál sea más grande, el orden cambia, de lo contrario, se lanza una excepción IndexOutOfBounds. Ver esta esencia .
vsp
@vsp DotIndicator implementa la interfaz SelectionIndicator, lo que significa que si tiene dos métodos útiles que pueden resolver su problema: int getNumberOfItems()y void setNumberOfItems(). En lugar de detectar la excepción, podría hacer algo como esto gist.github.com/MatthewTamlin/761c7338d271af29526edc7859480aef .
Helios
Para cualquiera que no siguiera la conversación esencial, en realidad había un error que ahora se ha solucionado. 3.0.2 es la última versión a partir de ahora.
Helios
18

ViewPagerIndicator no se ha actualizado desde 2012 y recibió varios errores que nunca se solucionaron.

Finalmente encontré una alternativa con esta biblioteca de luces que muestra buenos puntos para el viewpager, aquí está el enlace:

https://github.com/ongakuer/CircleIndicator

¡Fácil de implementar!

Yoann Hercouet
fuente
16

Pensé en publicar una solución más simple para el problema anterior y los números de los indicadores se pueden cambiar dinámicamente con solo cambiar un valor variable dotCounts=x lo que hice es así.

1) Cree un archivo xml en una carpeta dibujable para el indicador de página seleccionada llamado "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) Cree un archivo xml más para el indicador no seleccionado llamado "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) Ahora agregue agregue esta parte del código en el lugar donde desea mostrar los indicadores para ex a continuación viewPageren su archivo XML de diseño.

 <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) Agregue esta función en la parte superior de su archivo de actividad donde su diseño está inflado o el archivo xml anterior está relacionado con

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) Finalmente, en su método onCreate, agregue el siguiente código para hacer referencia a su diseño y manejar las posiciones seleccionadas de la página

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
fuente
13

Puede probar la biblioteca de Jake Wharton: https://github.com/JakeWharton/Android-ViewPagerIndicator

Joel Fernandes
fuente
¿Cómo puedo agregar puntos, no pestañas (como Nexus 5 launcher)?
Kfir Guy
@KfirGuy Se les conoce como indicadores. Puedes hacerlo usando la biblioteca que he mencionado anteriormente. Además, puedes verlo en acción aquí - play.google.com/store/apps/…
Joel Fernandes
@JoelFernandes parece que esa aplicación no está disponible en todos los países
34m0
9

La siguiente es mi solución propuesta.

  • Como necesitamos mostrar solo algunas imágenes en los buscapersonas, hemos evitado el uso engorroso de fragmentos.
    • Implementamos los indicadores de la página de visualización (los puntos inferiores sin ninguna biblioteca o complemento adicional)
    • Con solo tocar los indicadores de la página de visualización (los puntos) también está ocurriendo la navegación de la página.
    • No olvide agregar sus propias imágenes en los recursos.
    • Siéntase libre de comentar y mejorarlo.

A) Siguiente es my activity_main.xml

<?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>

primera imagen

ingrese la descripción de la imagen aquí

Ajit
fuente
Lo usé pero en el visor los puntos de desplazamiento no están cambiando
Aditya Vyas-Lakhan
1
Esta es la mejor respuesta.
Sandeep Londhe
1

Si alguien quiere construir un viewPagercon miniaturas como indicadores, el uso de esta biblioteca podría ser una opción: ThumbIndicator para viewPager que también funciona con enlaces de imágenes como recursos.

Mahdi Moqadasi
fuente
0

Así es como hice esto, algo similar a las soluciones anteriores. Solo asegúrate de llamar al método loadDots () después de descargar todas las imágenes .

    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
fuente