co.paulburke.android.textviewpager.TextViewPagerIndicator.java Source code

Java tutorial

Introduction

Here is the source code for co.paulburke.android.textviewpager.TextViewPagerIndicator.java

Source

/*
 * Copyright (C) 2012 Jake Wharton
 *
 * 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 co.paulburke.android.textviewpager;

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.view.DirectionalViewPager;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * Customized UnderlinePageIndicator from the ViewPageIndicator library that
 * emulates a scroll bar based on the orientation of the
 * {@link DirectionalViewPager} it's connected to.
 *
 * @author Jake Wharton
 * @author paulburke (ipaulpro) Modified to support {@link DirectionalViewPager}
 *         and better resemble a scroll bar.
 */
public class TextViewPagerIndicator extends View implements ViewPager.OnPageChangeListener {
    private static final String TAG = "TextViewPagerIndicator";

    private static final int FADE_FRAME_MS = 30;

    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private boolean mFades;
    private int mFadeDelay;
    private int mFadeLength;
    private int mFadeBy;

    private DirectionalViewPager mViewPager;
    private DirectionalViewPager.OnPageChangeListener mListener;
    private int mScrollState;
    private int mCurrentPage;
    private float mPositionOffset;

    private final Runnable mFadeRunnable = new Runnable() {
        @Override
        public void run() {
            if (!mFades)
                return;

            final int alpha = Math.max(mPaint.getAlpha() - mFadeBy, 0);
            mPaint.setAlpha(alpha);
            setBackgroundAlpha(alpha);
            invalidate();
            if (alpha > 0) {
                postDelayed(this, FADE_FRAME_MS);
            }
        }
    };

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

    public TextViewPagerIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.scrollPageIndicatorStyle);
    }

    public TextViewPagerIndicator(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        if (isInEditMode())
            return;

        final Resources res = getResources();

        // Load defaults from resources
        final boolean defaultFades = res.getBoolean(R.bool.scroll_indicator_fades);
        final int defaultFadeDelay = res.getInteger(R.integer.scroll_indicator_fade_delay);
        final int defaultFadeLength = res.getInteger(R.integer.scroll_indicator_fade_length);
        final int defaultSelectedColor = res.getColor(R.color.scroll_indicator_selected_color);

        // Retrieve styles attributes
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextViewPagerIndicator, defStyle, 0);

        setFades(a.getBoolean(R.styleable.TextViewPagerIndicator_fades, defaultFades));
        setSelectedColor(a.getColor(R.styleable.TextViewPagerIndicator_selectedColor, defaultSelectedColor));
        setFadeDelay(a.getInteger(R.styleable.TextViewPagerIndicator_fadeDelay, defaultFadeDelay));
        setFadeLength(a.getInteger(R.styleable.TextViewPagerIndicator_fadeLength, defaultFadeLength));

        Drawable background = a.getDrawable(R.styleable.TextViewPagerIndicator_android_background);
        if (background != null)
            setBackgroundDrawable(background);

        a.recycle();
    }

    public boolean getFades() {
        return mFades;
    }

    public void setFades(boolean fades) {
        if (fades != mFades) {
            mFades = fades;
            if (fades) {
                post(mFadeRunnable);
            } else {
                removeCallbacks(mFadeRunnable);
                mPaint.setAlpha(0xFF);
                setBackgroundAlpha(0xFF);
                invalidate();
            }
        }
    }

    public int getFadeDelay() {
        return mFadeDelay;
    }

    public void setFadeDelay(int fadeDelay) {
        mFadeDelay = fadeDelay;
    }

    public int getFadeLength() {
        return mFadeLength;
    }

    public void setFadeLength(int fadeLength) {
        mFadeLength = fadeLength;
        mFadeBy = 0xFF / (mFadeLength / FADE_FRAME_MS);
    }

    public int getSelectedColor() {
        return mPaint.getColor();
    }

    public void setSelectedColor(int selectedColor) {
        mPaint.setColor(selectedColor);
        invalidate();
    }

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

        if (mViewPager == null)
            return;

        final int count = mViewPager.getAdapter().getCount();
        if (count == 0)
            return;

        if (mCurrentPage >= count) {
            setCurrentItem(count - 1);
            return;
        }

        float left = 0f, top = 0f, right = 0f, bottom = 0f;

        final int paddingTop = getPaddingTop();
        final int paddingBottom = getPaddingBottom();
        final int paddingRight = getPaddingRight();
        final int paddingLeft = getPaddingLeft();

        if (isHorizontal()) {
            final float pageWidth = (getWidth() - paddingLeft - paddingRight) / (1f * count);
            left = paddingLeft + pageWidth * (mCurrentPage + mPositionOffset);
            right = left + pageWidth;
            top = 0f;
            bottom = getHeight();
        } else if (isVertical()) {
            final float pageHeight = (getHeight() - paddingTop - paddingBottom) / (1f * count);
            top = paddingTop + pageHeight * (mCurrentPage + mPositionOffset);
            bottom = top + pageHeight;
            left = 0f;
            right = getWidth();
        }

        canvas.drawRect(left, top, right, bottom, mPaint);
    }

    private boolean isHorizontal() {
        return mViewPager.getOrientation() == DirectionalViewPager.HORIZONTAL;
    }

    private boolean isVertical() {
        return mViewPager.getOrientation() == DirectionalViewPager.VERTICAL;
    }

    public void setViewPager(ViewPager viewPager) {
        if (mViewPager == viewPager) {
            return;
        }
        if (mViewPager != null) {
            // Clear us from the old pager.
            mViewPager.setOnPageChangeListener(null);
        }
        if (viewPager.getAdapter() == null) {
            throw new IllegalStateException("ViewPager does not have adapter instance.");
        }
        mViewPager = (DirectionalViewPager) viewPager;
        mViewPager.setOnPageChangeListener(this);
        mViewPager.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    show();
                }
                return false;
            }
        });
        invalidate();
        post(new Runnable() {
            @Override
            public void run() {
                if (mFades) {
                    post(mFadeRunnable);
                }
            }
        });
    }

    public void show() {
        removeCallbacks(mFadeRunnable);
        mPaint.setAlpha(0xFF);
        setBackgroundAlpha(0xFF);
        postDelayed(mFadeRunnable, mFadeDelay);
    }

    public void hide() {
        removeCallbacks(mFadeRunnable);
        post(mFadeRunnable);
    }

    public void setViewPager(ViewPager view, int initialPosition) {
        setViewPager(view);
        setCurrentItem(initialPosition);
    }

    public void setCurrentItem(int item) {
        if (mViewPager == null) {
            throw new IllegalStateException("ViewPager has not been bound.");
        }
        mViewPager.setCurrentItem(item);
        mCurrentPage = item;
        invalidate();
    }

    public void notifyDataSetChanged() {
        invalidate();
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        mScrollState = state;

        if (mListener != null) {
            mListener.onPageScrollStateChanged(state);
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        mCurrentPage = position;
        mPositionOffset = positionOffset;
        if (mFades) {
            if (positionOffsetPixels > 0) {
                removeCallbacks(mFadeRunnable);
                mPaint.setAlpha(0xFF);
                setBackgroundAlpha(0xFF);
            } else if (mScrollState != ViewPager.SCROLL_STATE_DRAGGING) {
                postDelayed(mFadeRunnable, mFadeDelay);
            }
        }
        invalidate();

        if (mListener != null) {
            mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
        }
    }

    @Override
    public void onPageSelected(int position) {
        if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
            mCurrentPage = position;
            mPositionOffset = 0;
            invalidate();
            mFadeRunnable.run();
        }
        if (mListener != null) {
            mListener.onPageSelected(position);
        }
    }

    public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
        mListener = listener;
    }

    private void setBackgroundAlpha(int alpha) {
        Drawable background = getBackground();
        if (background != null)
            background.setAlpha(alpha);
    }

    @Override
    public void onRestoreInstanceState(Parcelable state) {
        SavedState savedState = (SavedState) state;
        super.onRestoreInstanceState(savedState.getSuperState());
        mCurrentPage = savedState.currentPage;
        requestLayout();
    }

    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState savedState = new SavedState(superState);
        savedState.currentPage = mCurrentPage;
        return savedState;
    }

    static class SavedState extends BaseSavedState {
        int currentPage;

        public SavedState(Parcelable superState) {
            super(superState);
        }

        private SavedState(Parcel in) {
            super(in);
            currentPage = in.readInt();
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            super.writeToParcel(dest, flags);
            dest.writeInt(currentPage);
        }

        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
            @Override
            public SavedState createFromParcel(Parcel in) {
                return new SavedState(in);
            }

            @Override
            public SavedState[] newArray(int size) {
                return new SavedState[size];
            }
        };
    }
}