public class

PageIndicatorView

extends View

implements ViewPager.OnPageChangeListener

 java.lang.Object

↳View

↳androidx.wear.widget.drawer.PageIndicatorView

Gradle dependencies

compile group: 'androidx.wear', name: 'wear', version: '1.4.0-alpha01'

  • groupId: androidx.wear
  • artifactId: wear
  • version: 1.4.0-alpha01

Artifact androidx.wear:wear:1.4.0-alpha01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.wear:wear com.android.support:wear

Androidx class mapping:

androidx.wear.widget.drawer.PageIndicatorView android.support.wear.widget.drawer.PageIndicatorView

Overview

A page indicator for ViewPager based on which identifies the current page in relation to all available pages. Pages are represented as dots. The current page can be highlighted with a different color or size dot.

The default behavior is to fade out the dots when the pager is idle (not settling or being dragged). This can be changed with PageIndicatorView.setDotFadeWhenIdle(boolean).

Use PageIndicatorView.setPager(ViewPager) to connect this view to a pager instance.

Summary

Constructors
publicPageIndicatorView(Context context)

publicPageIndicatorView(Context context, AttributeSet attrs)

publicPageIndicatorView(Context context, AttributeSet attrs, int defStyleAttr)

Methods
public intgetDotColor()

Returns the color used for dots other than the selected page.

public intgetDotColorSelected()

Returns the color of the dot for the selected page.

public intgetDotFadeInDuration()

Returns the duration of the fade in duration, in milliseconds.

public intgetDotFadeOutDelay()

Sets the delay between the pager arriving at an idle state, and the fade out animation beginning, in milliseconds.

public intgetDotFadeOutDuration()

Returns the duration of fade out animation, in milliseconds.

public booleangetDotFadeWhenIdle()

Indicates if the dots fade out when the pager is idle.

public floatgetDotRadius()

Gets the radius of the page dots.

public floatgetDotRadiusSelected()

Gets the radius of the page dot for the selected page.

public intgetDotShadowColor()

Returns the color of the shadows drawn beneath the dots.

public floatgetDotShadowDx()

Returns the horizontal offset of shadows drawn beneath the dots.

public floatgetDotShadowDy()

Returns the vertical offset of shadows drawn beneath the dots.

public floatgetDotShadowRadius()

Sets the pixel radius of shadows drawn beneath the dots.

public floatgetDotSpacing()

Gets the center-to-center distance between page dots.

public voidnotifyDataSetChanged()

Notifies the view that the data set has changed.

protected voidonDraw(Canvas canvas)

protected voidonMeasure(int widthMeasureSpec, int heightMeasureSpec)

public voidonPageScrolled(int position, float positionOffset, int positionOffsetPixels)

public voidonPageScrollStateChanged(int state)

public voidonPageSelected(int position)

public voidsetDotColor(int color)

Sets the color used for dots other than the selected page.

public voidsetDotColorSelected(int color)

Sets the color of the dot for the selected page.

public voidsetDotFadeInDuration(int duration, java.util.concurrent.TimeUnit unit)

Sets the duration of the fade in animation.

public voidsetDotFadeOutDelay(int delay)

Sets the delay between the pager arriving at an idle state, and the fade out animation beginning, in milliseconds.

public voidsetDotFadeOutDuration(int duration, java.util.concurrent.TimeUnit unit)

Sets the duration of the fade out animation.

public voidsetDotFadeWhenIdle(boolean fade)

Sets whether the dots fade out when the pager is idle.

public voidsetDotRadius(int radius)

Sets the radius of the page dots.

public voidsetDotRadiusSelected(int radius)

Sets the radius of the page dot for the selected page.

public voidsetDotShadowColor(int color)

Sets the color of the shadows drawn beneath the dots.

public voidsetDotShadowDx(float dx)

Sets the horizontal offset of shadows drawn beneath the dots.

public voidsetDotShadowDy(float dy)

Sets the vertical offset of shadows drawn beneath the dots.

public voidsetDotShadowRadius(float radius)

Sets the pixel radius of shadows drawn beneath the dots.

public voidsetDotSpacing(int spacing)

Sets the center-to-center distance between page dots.

public voidsetPager(ViewPager pager)

Supplies the ViewPager instance, and attaches this views ViewPager.OnPageChangeListener to the pager.

public voidsetPagerAdapter(PagerAdapter adapter)

Sets the PagerAdapter.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public PageIndicatorView(Context context)

public PageIndicatorView(Context context, AttributeSet attrs)

public PageIndicatorView(Context context, AttributeSet attrs, int defStyleAttr)

Methods

public void setPager(ViewPager pager)

Supplies the ViewPager instance, and attaches this views ViewPager.OnPageChangeListener to the pager.

Parameters:

pager: the pager for the page indicator

public float getDotSpacing()

Gets the center-to-center distance between page dots.

Returns:

the distance between page dots

public void setDotSpacing(int spacing)

Sets the center-to-center distance between page dots.

Parameters:

spacing: the distance between page dots

public float getDotRadius()

Gets the radius of the page dots.

Returns:

the radius of the page dots

public void setDotRadius(int radius)

Sets the radius of the page dots.

Parameters:

radius: the radius of the page dots

public float getDotRadiusSelected()

Gets the radius of the page dot for the selected page.

Returns:

the radius of the selected page dot

public void setDotRadiusSelected(int radius)

Sets the radius of the page dot for the selected page.

Parameters:

radius: the radius of the selected page dot

public int getDotColor()

Returns the color used for dots other than the selected page.

Returns:

color the color used for dots other than the selected page

public void setDotColor(int color)

Sets the color used for dots other than the selected page.

Parameters:

color: the color used for dots other than the selected page

public int getDotColorSelected()

Returns the color of the dot for the selected page.

Returns:

the color used for the selected page dot

public void setDotColorSelected(int color)

Sets the color of the dot for the selected page.

Parameters:

color: the color of the dot for the selected page

public boolean getDotFadeWhenIdle()

Indicates if the dots fade out when the pager is idle.

Returns:

whether the dots fade out when idle

public void setDotFadeWhenIdle(boolean fade)

Sets whether the dots fade out when the pager is idle.

Parameters:

fade: whether the dots fade out when idle

public int getDotFadeOutDuration()

Returns the duration of fade out animation, in milliseconds.

Returns:

the duration of the fade out animation, in milliseconds

public void setDotFadeOutDuration(int duration, java.util.concurrent.TimeUnit unit)

Sets the duration of the fade out animation.

Parameters:

duration: the duration of the fade out animation

public int getDotFadeInDuration()

Returns the duration of the fade in duration, in milliseconds.

Returns:

the duration of the fade in duration, in milliseconds

public void setDotFadeInDuration(int duration, java.util.concurrent.TimeUnit unit)

Sets the duration of the fade in animation.

Parameters:

duration: the duration of the fade in animation

public int getDotFadeOutDelay()

Sets the delay between the pager arriving at an idle state, and the fade out animation beginning, in milliseconds.

Returns:

the delay before the fade out animation begins, in milliseconds

public void setDotFadeOutDelay(int delay)

Sets the delay between the pager arriving at an idle state, and the fade out animation beginning, in milliseconds.

Parameters:

delay: the delay before the fade out animation begins, in milliseconds

public float getDotShadowRadius()

Sets the pixel radius of shadows drawn beneath the dots.

Returns:

the pixel radius of shadows rendered beneath the dots

public void setDotShadowRadius(float radius)

Sets the pixel radius of shadows drawn beneath the dots.

Parameters:

radius: the pixel radius of shadows rendered beneath the dots

public float getDotShadowDx()

Returns the horizontal offset of shadows drawn beneath the dots.

Returns:

the horizontal offset of shadows drawn beneath the dots

public void setDotShadowDx(float dx)

Sets the horizontal offset of shadows drawn beneath the dots.

Parameters:

dx: the horizontal offset of shadows drawn beneath the dots

public float getDotShadowDy()

Returns the vertical offset of shadows drawn beneath the dots.

Returns:

the vertical offset of shadows drawn beneath the dots

public void setDotShadowDy(float dy)

Sets the vertical offset of shadows drawn beneath the dots.

Parameters:

dy: the vertical offset of shadows drawn beneath the dots

public int getDotShadowColor()

Returns the color of the shadows drawn beneath the dots.

Returns:

the color of the shadows drawn beneath the dots

public void setDotShadowColor(int color)

Sets the color of the shadows drawn beneath the dots.

Parameters:

color: the color of the shadows drawn beneath the dots

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)

public void onPageSelected(int position)

public void onPageScrollStateChanged(int state)

public void setPagerAdapter(PagerAdapter adapter)

Sets the PagerAdapter.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

protected void onDraw(Canvas canvas)

public void notifyDataSetChanged()

Notifies the view that the data set has changed.

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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.
 */

package androidx.wear.widget.drawer;

import android.animation.Animator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.Shader.TileMode;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager.widget.ViewPager.OnPageChangeListener;
import androidx.wear.R;
import androidx.wear.widget.SimpleAnimatorListener;

import java.util.concurrent.TimeUnit;

/**
 * A page indicator for {@link ViewPager} based on {@link
 * androidx.wear.view.DotsPageIndicator} which identifies the current page in relation to
 * all available pages. Pages are represented as dots. The current page can be highlighted with a
 * different color or size dot.
 *
 * <p>The default behavior is to fade out the dots when the pager is idle (not settling or being
 * dragged). This can be changed with {@link #setDotFadeWhenIdle(boolean)}.
 *
 * <p>Use {@link #setPager(ViewPager)} to connect this view to a pager instance.
 *
 */
@RestrictTo(Scope.LIBRARY)
public class PageIndicatorView extends View implements OnPageChangeListener {

    private static final String TAG = "Dots";
    private final Paint mDotPaint;
    private final Paint mDotPaintShadow;
    private final Paint mDotPaintSelected;
    private final Paint mDotPaintShadowSelected;
    private int mDotSpacing;
    private float mDotRadius;
    private float mDotRadiusSelected;
    private int mDotColor;
    private int mDotColorSelected;
    private boolean mDotFadeWhenIdle;
    int mDotFadeOutDelay;
    int mDotFadeOutDuration;
    private int mDotFadeInDuration;
    private float mDotShadowDx;
    private float mDotShadowDy;
    private float mDotShadowRadius;
    private int mDotShadowColor;
    private PagerAdapter mAdapter;
    private int mNumberOfPositions;
    private int mSelectedPosition;
    private int mCurrentViewPagerState;
    boolean mVisible;

    public PageIndicatorView(Context context) {
        this(context, null);
    }

    public PageIndicatorView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public PageIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        final TypedArray a =
                getContext()
                        .obtainStyledAttributes(
                                attrs, R.styleable.PageIndicatorView, defStyleAttr,
                                R.style.WsPageIndicatorViewStyle);

        mDotSpacing = a.getDimensionPixelOffset(
                R.styleable.PageIndicatorView_wsPageIndicatorDotSpacing, 0);
        mDotRadius = a.getDimension(R.styleable.PageIndicatorView_wsPageIndicatorDotRadius, 0);
        mDotRadiusSelected =
                a.getDimension(R.styleable.PageIndicatorView_wsPageIndicatorDotRadiusSelected, 0);
        mDotColor = a.getColor(R.styleable.PageIndicatorView_wsPageIndicatorDotColor, 0);
        mDotColorSelected = a
                .getColor(R.styleable.PageIndicatorView_wsPageIndicatorDotColorSelected, 0);
        mDotFadeOutDelay =
                a.getInt(R.styleable.PageIndicatorView_wsPageIndicatorDotFadeOutDelay, 0);
        mDotFadeOutDuration =
                a.getInt(R.styleable.PageIndicatorView_wsPageIndicatorDotFadeOutDuration, 0);
        mDotFadeInDuration =
                a.getInt(R.styleable.PageIndicatorView_wsPageIndicatorDotFadeInDuration, 0);
        mDotFadeWhenIdle =
                a.getBoolean(R.styleable.PageIndicatorView_wsPageIndicatorDotFadeWhenIdle, false);
        mDotShadowDx = a.getDimension(R.styleable.PageIndicatorView_wsPageIndicatorDotShadowDx, 0);
        mDotShadowDy = a.getDimension(R.styleable.PageIndicatorView_wsPageIndicatorDotShadowDy, 0);
        mDotShadowRadius =
                a.getDimension(R.styleable.PageIndicatorView_wsPageIndicatorDotShadowRadius, 0);
        mDotShadowColor =
                a.getColor(R.styleable.PageIndicatorView_wsPageIndicatorDotShadowColor, 0);
        a.recycle();

        mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mDotPaint.setColor(mDotColor);
        mDotPaint.setStyle(Style.FILL);

        mDotPaintSelected = new Paint(Paint.ANTI_ALIAS_FLAG);
        mDotPaintSelected.setColor(mDotColorSelected);
        mDotPaintSelected.setStyle(Style.FILL);
        mDotPaintShadow = new Paint(Paint.ANTI_ALIAS_FLAG);
        mDotPaintShadowSelected = new Paint(Paint.ANTI_ALIAS_FLAG);

        mCurrentViewPagerState = ViewPager.SCROLL_STATE_IDLE;
        if (isInEditMode()) {
            // When displayed in layout preview:
            // Simulate 5 positions, currently on the 3rd position.
            mNumberOfPositions = 5;
            mSelectedPosition = 2;
            mDotFadeWhenIdle = false;
        }

        if (mDotFadeWhenIdle) {
            mVisible = false;
            animate().alpha(0f).setStartDelay(2000).setDuration(mDotFadeOutDuration).start();
        } else {
            animate().cancel();
            setAlpha(1.0f);
        }
        updateShadows();
    }

    private void updateShadows() {
        updateDotPaint(
                mDotPaint, mDotPaintShadow, mDotRadius, mDotShadowRadius, mDotColor,
                mDotShadowColor);
        updateDotPaint(
                mDotPaintSelected,
                mDotPaintShadowSelected,
                mDotRadiusSelected,
                mDotShadowRadius,
                mDotColorSelected,
                mDotShadowColor);
    }

    private void updateDotPaint(
            Paint dotPaint,
            Paint shadowPaint,
            float baseRadius,
            float shadowRadius,
            int color,
            int shadowColor) {
        float radius = baseRadius + shadowRadius;
        float shadowStart = baseRadius / radius;
        Shader gradient =
                new RadialGradient(
                        0,
                        0,
                        radius,
                        new int[]{shadowColor, shadowColor, Color.TRANSPARENT},
                        new float[]{0f, shadowStart, 1f},
                        TileMode.CLAMP);

        shadowPaint.setShader(gradient);
        dotPaint.setColor(color);
        dotPaint.setStyle(Style.FILL);
    }

    /**
     * Supplies the ViewPager instance, and attaches this views {@link OnPageChangeListener} to the
     * pager.
     *
     * @param pager the pager for the page indicator
     */
    public void setPager(ViewPager pager) {
        pager.addOnPageChangeListener(this);
        setPagerAdapter(pager.getAdapter());
        mAdapter = pager.getAdapter();
        if (mAdapter != null && mAdapter.getCount() > 0) {
            positionChanged(0);
        }
    }

    /**
     * Gets the center-to-center distance between page dots.
     *
     * @return the distance between page dots
     */
    public float getDotSpacing() {
        return mDotSpacing;
    }

    /**
     * Sets the center-to-center distance between page dots.
     *
     * @param spacing the distance between page dots
     */
    public void setDotSpacing(int spacing) {
        if (mDotSpacing != spacing) {
            mDotSpacing = spacing;
            requestLayout();
        }
    }

    /**
     * Gets the radius of the page dots.
     *
     * @return the radius of the page dots
     */
    public float getDotRadius() {
        return mDotRadius;
    }

    /**
     * Sets the radius of the page dots.
     *
     * @param radius the radius of the page dots
     */
    public void setDotRadius(int radius) {
        if (mDotRadius != radius) {
            mDotRadius = radius;
            updateShadows();
            invalidate();
        }
    }

    /**
     * Gets the radius of the page dot for the selected page.
     *
     * @return the radius of the selected page dot
     */
    public float getDotRadiusSelected() {
        return mDotRadiusSelected;
    }

    /**
     * Sets the radius of the page dot for the selected page.
     *
     * @param radius the radius of the selected page dot
     */
    public void setDotRadiusSelected(int radius) {
        if (mDotRadiusSelected != radius) {
            mDotRadiusSelected = radius;
            updateShadows();
            invalidate();
        }
    }

    /**
     * Returns the color used for dots other than the selected page.
     *
     * @return color the color used for dots other than the selected page
     */
    public int getDotColor() {
        return mDotColor;
    }

    /**
     * Sets the color used for dots other than the selected page.
     *
     * @param color the color used for dots other than the selected page
     */
    public void setDotColor(int color) {
        if (mDotColor != color) {
            mDotColor = color;
            invalidate();
        }
    }

    /**
     * Returns the color of the dot for the selected page.
     *
     * @return the color used for the selected page dot
     */
    public int getDotColorSelected() {
        return mDotColorSelected;
    }

    /**
     * Sets the color of the dot for the selected page.
     *
     * @param color the color of the dot for the selected page
     */
    public void setDotColorSelected(int color) {
        if (mDotColorSelected != color) {
            mDotColorSelected = color;
            invalidate();
        }
    }

    /**
     * Indicates if the dots fade out when the pager is idle.
     *
     * @return whether the dots fade out when idle
     */
    public boolean getDotFadeWhenIdle() {
        return mDotFadeWhenIdle;
    }

    /**
     * Sets whether the dots fade out when the pager is idle.
     *
     * @param fade whether the dots fade out when idle
     */
    public void setDotFadeWhenIdle(boolean fade) {
        mDotFadeWhenIdle = fade;
        if (!fade) {
            fadeIn();
        }
    }

    /**
     * Returns the duration of fade out animation, in milliseconds.
     *
     * @return the duration of the fade out animation, in milliseconds
     */
    public int getDotFadeOutDuration() {
        return mDotFadeOutDuration;
    }

    /**
     * Sets the duration of the fade out animation.
     *
     * @param duration the duration of the fade out animation
     */
    public void setDotFadeOutDuration(int duration, TimeUnit unit) {
        mDotFadeOutDuration = (int) TimeUnit.MILLISECONDS.convert(duration, unit);
    }

    /**
     * Returns the duration of the fade in duration, in milliseconds.
     *
     * @return the duration of the fade in duration, in milliseconds
     */
    public int getDotFadeInDuration() {
        return mDotFadeInDuration;
    }

    /**
     * Sets the duration of the fade in animation.
     *
     * @param duration the duration of the fade in animation
     */
    public void setDotFadeInDuration(int duration, TimeUnit unit) {
        mDotFadeInDuration = (int) TimeUnit.MILLISECONDS.convert(duration, unit);
    }

    /**
     * Sets the delay between the pager arriving at an idle state, and the fade out animation
     * beginning, in milliseconds.
     *
     * @return the delay before the fade out animation begins, in milliseconds
     */
    public int getDotFadeOutDelay() {
        return mDotFadeOutDelay;
    }

    /**
     * Sets the delay between the pager arriving at an idle state, and the fade out animation
     * beginning, in milliseconds.
     *
     * @param delay the delay before the fade out animation begins, in milliseconds
     */
    public void setDotFadeOutDelay(int delay) {
        mDotFadeOutDelay = delay;
    }

    /**
     * Sets the pixel radius of shadows drawn beneath the dots.
     *
     * @return the pixel radius of shadows rendered beneath the dots
     */
    public float getDotShadowRadius() {
        return mDotShadowRadius;
    }

    /**
     * Sets the pixel radius of shadows drawn beneath the dots.
     *
     * @param radius the pixel radius of shadows rendered beneath the dots
     */
    public void setDotShadowRadius(float radius) {
        if (mDotShadowRadius != radius) {
            mDotShadowRadius = radius;
            updateShadows();
            invalidate();
        }
    }

    /**
     * Returns the horizontal offset of shadows drawn beneath the dots.
     *
     * @return the horizontal offset of shadows drawn beneath the dots
     */
    public float getDotShadowDx() {
        return mDotShadowDx;
    }

    /**
     * Sets the horizontal offset of shadows drawn beneath the dots.
     *
     * @param dx the horizontal offset of shadows drawn beneath the dots
     */
    public void setDotShadowDx(float dx) {
        mDotShadowDx = dx;
        invalidate();
    }

    /**
     * Returns the vertical offset of shadows drawn beneath the dots.
     *
     * @return the vertical offset of shadows drawn beneath the dots
     */
    public float getDotShadowDy() {
        return mDotShadowDy;
    }

    /**
     * Sets the vertical offset of shadows drawn beneath the dots.
     *
     * @param dy the vertical offset of shadows drawn beneath the dots
     */
    public void setDotShadowDy(float dy) {
        mDotShadowDy = dy;
        invalidate();
    }

    /**
     * Returns the color of the shadows drawn beneath the dots.
     *
     * @return the color of the shadows drawn beneath the dots
     */
    public int getDotShadowColor() {
        return mDotShadowColor;
    }

    /**
     * Sets the color of the shadows drawn beneath the dots.
     *
     * @param color the color of the shadows drawn beneath the dots
     */
    public void setDotShadowColor(int color) {
        mDotShadowColor = color;
        updateShadows();
        invalidate();
    }

    private void positionChanged(int position) {
        mSelectedPosition = position;
        invalidate();
    }

    private void updateNumberOfPositions() {
        int count = mAdapter.getCount();
        if (count != mNumberOfPositions) {
            mNumberOfPositions = count;
            requestLayout();
        }
    }

    private void fadeIn() {
        mVisible = true;
        animate().cancel();
        animate().alpha(1f).setStartDelay(0).setDuration(mDotFadeInDuration).start();
    }

    private void fadeOut(long delayMillis) {
        mVisible = false;
        animate().cancel();
        animate().alpha(0f).setStartDelay(delayMillis).setDuration(mDotFadeOutDuration).start();
    }

    private void fadeInOut() {
        mVisible = true;
        animate().cancel();
        animate()
                .alpha(1f)
                .setStartDelay(0)
                .setDuration(mDotFadeInDuration)
                .setListener(
                        new SimpleAnimatorListener() {
                            @Override
                            public void onAnimationComplete(Animator animator) {
                                mVisible = false;
                                animate()
                                        .alpha(0f)
                                        .setListener(null)
                                        .setStartDelay(mDotFadeOutDelay)
                                        .setDuration(mDotFadeOutDuration)
                                        .start();
                            }
                        })
                .start();
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (mDotFadeWhenIdle) {
            if (mCurrentViewPagerState == ViewPager.SCROLL_STATE_DRAGGING) {
                if (positionOffset != 0) {
                    if (!mVisible) {
                        fadeIn();
                    }
                } else {
                    if (mVisible) {
                        fadeOut(0);
                    }
                }
            }
        }
    }

    @Override
    public void onPageSelected(int position) {
        if (position != mSelectedPosition) {
            positionChanged(position);
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        if (mCurrentViewPagerState != state) {
            mCurrentViewPagerState = state;
            if (mDotFadeWhenIdle) {
                if (state == ViewPager.SCROLL_STATE_IDLE) {
                    if (mVisible) {
                        fadeOut(mDotFadeOutDelay);
                    } else {
                        fadeInOut();
                    }
                }
            }
        }
    }

    /**
     * Sets the {@link PagerAdapter}.
     */
    public void setPagerAdapter(PagerAdapter adapter) {
        mAdapter = adapter;
        if (mAdapter != null) {
            updateNumberOfPositions();
            if (mDotFadeWhenIdle) {
                fadeInOut();
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int totalWidth;
        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
            totalWidth = MeasureSpec.getSize(widthMeasureSpec);
        } else {
            int contentWidth = mNumberOfPositions * mDotSpacing;
            totalWidth = contentWidth + getPaddingLeft() + getPaddingRight();
        }
        int totalHeight;
        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
            totalHeight = MeasureSpec.getSize(heightMeasureSpec);
        } else {
            float maxRadius =
                    Math.max(mDotRadius + mDotShadowRadius, mDotRadiusSelected + mDotShadowRadius);
            int contentHeight = (int) Math.ceil(maxRadius * 2);
            contentHeight = (int) (contentHeight + mDotShadowDy);
            totalHeight = contentHeight + getPaddingTop() + getPaddingBottom();
        }
        setMeasuredDimension(
                resolveSizeAndState(totalWidth, widthMeasureSpec, 0),
                resolveSizeAndState(totalHeight, heightMeasureSpec, 0));
    }

    @Override
    protected void onDraw(@NonNull Canvas canvas) {
        super.onDraw(canvas);

        if (mNumberOfPositions > 1) {
            float dotCenterLeft = getPaddingLeft() + (mDotSpacing / 2f);
            float dotCenterTop = getHeight() / 2f;
            canvas.save();
            canvas.translate(dotCenterLeft, dotCenterTop);
            for (int i = 0; i < mNumberOfPositions; i++) {
                if (i == mSelectedPosition) {
                    float radius = mDotRadiusSelected + mDotShadowRadius;
                    canvas.drawCircle(mDotShadowDx, mDotShadowDy, radius, mDotPaintShadowSelected);
                    canvas.drawCircle(0, 0, mDotRadiusSelected, mDotPaintSelected);
                } else {
                    float radius = mDotRadius + mDotShadowRadius;
                    canvas.drawCircle(mDotShadowDx, mDotShadowDy, radius, mDotPaintShadow);
                    canvas.drawCircle(0, 0, mDotRadius, mDotPaint);
                }
                canvas.translate(mDotSpacing, 0);
            }
            canvas.restore();
        }
    }

    /**
     * Notifies the view that the data set has changed.
     */
    public void notifyDataSetChanged() {
        if (mAdapter != null && mAdapter.getCount() > 0) {
            updateNumberOfPositions();
        }
    }
}