Java tutorial
/* * 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 com.example.anumbrella.viewpager; 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.MotionEventCompat; import android.support.v4.view.ViewConfigurationCompat; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; /** * Created by anumbrella on 15-11-4. * <p/> * <p/> * ??Jake Wharton,??, * <p/> * UnderlinePagerIndicator???? */ public class UnderlinePagerIndicator extends View implements PagerIndicator { /** * */ private static final int INVALID_POINTER = -1; /** * ??? */ private static final int FADE_TIME = 30; /** * ? */ private boolean mFades; /** * */ private int mFadeDelay; /** * */ private int mFadeLength; private ViewPager mViewPager; /** * ViewPager??? */ private ViewPager.OnPageChangeListener pageChangeListener; /** * ?? */ private int mCurrentPage; /** * ?? */ private int mTouchSlop; /** * ? */ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); /** * */ private boolean isDragging = false; /** * */ private int mActivePointerId = INVALID_POINTER; /** * ?x?? */ private float mLastMotionX = -1; /** * ??? */ private int mFadeBy; /** * ???? */ private float mPositionOffset; /** * ?? */ private int mScrollState; /** * ??? */ private final Runnable mFadeRunable = new Runnable() { @Override public void run() { if (!mFades) { return; } //?????0 final int alpha = Math.max(mPaint.getAlpha() - mFadeBy, 0); mPaint.setAlpha(alpha); invalidate(); //?0??? if (alpha > 0) { postDelayed(this, FADE_TIME); } } }; public UnderlinePagerIndicator(Context context) { this(context, null); } public UnderlinePagerIndicator(Context context, AttributeSet attrs) { this(context, attrs, R.attr.vpiUnderlinePagerIndicatorStyle); } public UnderlinePagerIndicator(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // if (isInEditMode()) { return; } //?? final Resources res = getResources(); // //? final boolean defaultFades = res.getBoolean(R.bool.default_underline_indicator_fades); // final int defaultFadeDelay = res.getInteger(R.integer.default_underline_indicator_fade_delay); // final int defaultFadeLength = res.getInteger(R.integer.default_underline_indicator_fade_length); //?? final int defaultSelectedColor = res.getColor(R.color.default_underline_indicator_selected_color); //?xml TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.UnderlinePagerIndicator, defStyle, 0); setFades(array.getBoolean(R.styleable.UnderlinePagerIndicator_fades, defaultFades)); setSelectedColor(array.getColor(R.styleable.UnderlinePagerIndicator_selectedColor, defaultSelectedColor)); setFadeDelay(array.getInteger(R.styleable.UnderlinePagerIndicator_fadeDelay, defaultFadeDelay)); setFadeLength(array.getInteger(R.styleable.UnderlinePagerIndicator_fadeLength, defaultFadeLength)); Drawable background = array.getDrawable(R.styleable.UnderlinePagerIndicator_android_background); if (background != null) { setBackgroundDrawable(background); } array.recycle(); final ViewConfiguration configuration = ViewConfiguration.get(context); //????(?????) mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); } /** * ? * * @param isFades */ public void setFades(boolean isFades) { if (mFades != isFades) { mFades = isFades; if (mFades) { post(mFadeRunable); } else { //?,? removeCallbacks(mFadeRunable); /** * ?0---255,?? * 0xFF = 255 */ mPaint.setAlpha(0xFF); invalidate(); } } } /** * * * @param fadeDelay */ public void setFadeDelay(int fadeDelay) { mFadeDelay = fadeDelay; } /** * * * @param fadeLength */ public void setFadeLength(int fadeLength) { mFadeLength = fadeLength; //??? // 0xFF = 255 , // :mFadeLength = 400 ; FADE_TIME = 30 // mFadeBy = 19.125 // mFadeBy19 mFadeBy = 0xFF / (mFadeLength / FADE_TIME); } /** * ? * * @param selectedColor */ public void setSelectedColor(int selectedColor) { mPaint.setColor(selectedColor); invalidate(); } public boolean getFades() { return mFades; } public int getFadeDelay() { return mFadeDelay; } public int getFadeLength() { return mFadeLength; } public int getSelectedColor() { return mPaint.getColor(); } /** * */ @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; } final float paddingLeft = getPaddingLeft(); final float paddingRight = getPaddingRight(); final float pageWidth = (getWidth() - paddingLeft - paddingRight) / (1f * count); final float left = paddingLeft + pageWidth * (mCurrentPage + mPositionOffset); final float top = getPaddingTop(); final float bottom = getHeight() - getPaddingBottom(); final float right = left + pageWidth; // canvas.drawRect(left, top, right, bottom, mPaint); } /** * ?? * * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { if (super.onTouchEvent(event)) { return true; } if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) { return false; } /** * ACTION_POINTER_DOWN:?? * ACTION_POINTER_UP:??? * ACTION_MASK & ACTION ACTION_POINTER_DOWNACTION_POINTER_UP */ final int action = event.getAction() & MotionEventCompat.ACTION_MASK; switch (action) { case MotionEvent.ACTION_DOWN: //getPointerId0getPointerCount-1,,?0 mActivePointerId = MotionEventCompat.getPointerId(event, 0); mLastMotionX = event.getX(); break; case MotionEvent.ACTION_MOVE: //?pointer?index final int activePointerIndex = MotionEventCompat.findPointerIndex(event, mActivePointerId); //?pointerx? final float x = MotionEventCompat.getX(event, activePointerIndex); //?x?? final float deltaX = x - mLastMotionX; if (!isDragging) { if (Math.abs(deltaX) > mTouchSlop) { isDragging = true; } } if (isDragging) { mLastMotionX = x; if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) { mViewPager.fakeDragBy(deltaX); } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: //?? if (!isDragging) { final int count = mViewPager.getAdapter().getCount(); final int width = getWidth(); //?? final float halfWidth = width / 2f; final float sixthWidth = width / 6f; //,? if ((mCurrentPage > 0) && (event.getX() < halfWidth - sixthWidth)) { if (action != MotionEvent.ACTION_CANCEL) { mViewPager.setCurrentItem(mCurrentPage - 1); } return true; } else if ((mCurrentPage < count - 1) && (event.getX() > halfWidth + sixthWidth)) { if (action != MotionEvent.ACTION_CANCEL) { mViewPager.setCurrentItem(mCurrentPage + 1); } return true; } } isDragging = false; mActivePointerId = INVALID_POINTER; if (mViewPager.isFakeDragging()) { mViewPager.endFakeDrag(); } break; case MotionEventCompat.ACTION_POINTER_DOWN: final int index = MotionEventCompat.getActionIndex(event); mLastMotionX = MotionEventCompat.getX(event, index); mActivePointerId = MotionEventCompat.getPointerId(event, index); break; case MotionEventCompat.ACTION_POINTER_UP: final int pointerIndex = MotionEventCompat.getActionIndex(event); final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex); if (pointerId == mActivePointerId) { final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mActivePointerId = MotionEventCompat.getPointerId(event, newPointerIndex); } mLastMotionX = MotionEventCompat.getX(event, MotionEventCompat.findPointerIndex(event, mActivePointerId)); break; } return true; } @Override public void setViewPager(ViewPager viewPager) { if (viewPager == mViewPager) { return; } if (mViewPager != null) { //?? mViewPager.setOnPageChangeListener(null); } if (viewPager.getAdapter() == null) { throw new IllegalStateException("ViewPager dose not have adapter instance!"); } mViewPager = viewPager; //?? mViewPager.setOnPageChangeListener(this); invalidate(); //? post(new Runnable() { @Override public void run() { if (mFades) { post(mFadeRunable); } } }); } @Override public void setViewPager(ViewPager viewPager, int initialPosition) { setViewPager(viewPager); setCurrentItem(initialPosition); } @Override public void setCurrentItem(int item) { if (mViewPager == null) { throw new IllegalStateException("ViewPager has not been found!"); } mCurrentPage = item; mViewPager.setCurrentItem(item); invalidate(); } @Override public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { pageChangeListener = listener; } @Override public void notifyDataSetChanged() { invalidate(); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { mCurrentPage = position; mPositionOffset = positionOffset; if (mFades) { //?? if (positionOffsetPixels > 0) { removeCallbacks(mFadeRunable); mPaint.setAlpha(0xFF); //,? } else if (mScrollState != ViewPager.SCROLL_STATE_DRAGGING) { postDelayed(mFadeRunable, mFadeDelay); } } invalidate(); if (pageChangeListener != null) { pageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } } @Override public void onPageSelected(int position) { //?? if (mScrollState == ViewPager.SCROLL_STATE_IDLE) { mCurrentPage = position; mPositionOffset = 0; invalidate(); mFadeRunable.run(); } if (pageChangeListener != null) { pageChangeListener.onPageSelected(position); } } @Override public void onPageScrollStateChanged(int state) { mScrollState = state; if (pageChangeListener != null) { pageChangeListener.onPageScrollStateChanged(state); } } /** * ???? * * @param state */ @Override public void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); mCurrentPage = savedState.currentPage; requestLayout(); } /** * ???? * * @return */ @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState savedState = new SavedState(superState); savedState.currentPage = mCurrentPage; return savedState; } /** * ?,BaseSavedState */ public static class SavedState extends BaseSavedState { private int currentPage; private SavedState(Parcel in) { super(in); currentPage = in.readInt(); } public SavedState(Parcelable superState) { super(superState); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(currentPage); } public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel source) { return new SavedState(source); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } }