在 Android 控件中,ViewPager 一直算是使用率比較高的控件,包括首頁的banner,tab頁的切換都能見到ViewPager的身影。
viewpager
來源自 v4 支持包 (android.support.v4.view.ViewPager
),用於左右切換界面實現tab的效果。其使用方法與 ListView
相似都是搭配一個adapter進行數據適配。java
<android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="140dp" />
一般Viewpager直接往佈局文件裏面添加就能夠了,雖然ViewPager是一個容器類,繼承自 ViewGroup,但不建議往裏面添加子view。
以後能夠在代碼中像調用普通控件同樣經過 findViewById(R.id.viewpager)
經過id獲取viewpager控件。android
PagerAdapter pagerAdapter = new PagerAdapter() { // @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } //返回要滑動的VIew的個數 @Override public int getCount() { return viewList.size(); } //從當前container中刪除指定位置(position)的View; @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(viewList.get(position)); } @Override public int getItemPosition(Object object) { return super.getItemPosition(object); } @Override public CharSequence getPageTitle(int position) { return titleList.get(position); } //作了兩件事,第一:將當前視圖添加到container中,第二:返回當前View @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(viewList.get(position)); return viewList.get(position); } };
PagerAdapter 支持數據集合的改變,能夠調用notifyDataSetChanged
方法來進行更新。和BaseAdapter
很是類似。git
viewPager = (ViewPager) findViewById(R.id.viewpager); LayoutInflater inflater=getLayoutInflater(); view1 = inflater.inflate(R.layout.layout1, null); view2 = inflater.inflate(R.layout.layout2,null); view3 = inflater.inflate(R.layout.layout3, null); viewList = new ArrayList<View>();// 將要分頁顯示的View裝入數組中 viewList.add(view1); viewList.add(view2); viewList.add(view3); //初始化 pagerAdapter PagerAdapter pagerAdapter = new PagerAdapter() {...} viewPager.setAdapter(pagerAdapter);
此時PagerAdapter包含了viewList數據,此時就能顯示到Viewpager中。github
這兩個類都屬於v4 support包中的類,兩個都是是ViewPager的一個關於當前頁面、上一個頁面和下一個頁面的指示器。
其做爲ViewPager控件的一個子控件被被添加在XML佈局文件中,每一個頁面的標題是經過適配器的getPageTitle(int)
函數提供給ViewPager的。
但二者又有不一樣:
一、 PagerTabStrip 是可交互的,點哪滾到哪;
二、 PagerTabStrip 在當前頁面下,會有一個下劃線條來提示當前頁面的Tab是哪一個。
這裏以 PagerTabStrip 爲例canvas
添加布局數組
<android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="140dp" android:layout_gravity="center"> <android.support.v4.view.PagerTabStrip android:id="@+id/pagertab" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top"/> </android.support.v4.view.ViewPager>
添加代碼app
titleList = new ArrayList<String>();// 每一個頁面的Title數據 titleList.add("1111"); titleList.add("2222"); titleList.add("3333");
經過PagerAdaper的getPageTitle(int position)
來設置標題ide
@Override public CharSequence getPageTitle(int position) { return titleList.get(position); }
但因爲 PagerTabStrip 的侷限性,你們通常都會自定義一個指示器,經過ViewPager.OnPageChangeListener
綁定。
同時安利一下 google design 包裏面的 TabLayout
和 最新推出的Bottom navigation
。函數
這是一款我剛寫的開源庫,起初寫這個是由於我想要一個能夠高度自定義化的輪播器,它包括了一下幾個特色:oop
使用本身項目中的ImageLoader,而不是被迫使用庫中的圖片加載器;
庫中內置幾款經常使用的指示器,也能夠建立本身想要的指示器;
豐富多彩的轉場動畫,亦能夠發揮你的創意創造新的特效;
能夠爲每一頁創建動畫效果。
通常的ViewPager播放到最後一個位置時,若要返回到第一個位置則必須從右向左,做爲Banner時這是不天然的過渡效果。
咱們知道ViewPager顯示的個數是由PagerAdaper的getCount()
方法決定的,既然如此那咱們能夠給它賦予一個極大的值使ViewPager不斷向右輪播,這也是整個無限輪播的核心思想。
public class InfinitePagerAdapter extends PagerAdapter { private static final String TAG = "InfinitePagerAdapter"; private static final boolean DEBUG = false; private BaseSliderAdapter adapter; public InfinitePagerAdapter(BaseSliderAdapter adapter) { this.adapter = adapter; adapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { notifyDataSetChanged(); super.onChanged(); } }); } public BaseSliderAdapter getRealAdapter() { return this.adapter; } @Override public CharSequence getPageTitle(int position) { return adapter.getPageTitle(position % getRealCount()); } @Override public int getCount() { // warning: scrolling to very high values (1,000,000+) results in // strange drawing behaviour if (getRealCount() == 0) return 0; if (getRealCount() == 1) return 1; return Integer.MAX_VALUE; } /** * @return the {@link #getCount()} result of the wrapped adapter */ public int getRealCount() { return adapter.getCount(); } public BaseSliderView getSliderView(int position) { return adapter.getSliderView(position % getRealCount()); } @Override public Object instantiateItem(ViewGroup container, int position) { if (getRealCount() == 0) { return null; } int virtualPosition = position % getRealCount(); debug("instantiateItem: real position: " + position); debug("instantiateItem: virtual position: " + virtualPosition); // only expose virtual position to the inner adapter return adapter.instantiateItem(container, virtualPosition); } @Override public void destroyItem(ViewGroup container, int position, Object object) { if (getRealCount() == 0) { return; } int virtualPosition = position % getRealCount(); debug("destroyItem: real position: " + position); debug("destroyItem: virtual position: " + virtualPosition); // only expose virtual position to the inner adapter adapter.destroyItem(container, virtualPosition, object); } /* * Delegate rest of methods directly to the inner adapter. */ @Override public void finishUpdate(ViewGroup container) { adapter.finishUpdate(container); } @Override public boolean isViewFromObject(View view, Object object) { return adapter.isViewFromObject(view, object); } @Override public void restoreState(Parcelable bundle, ClassLoader classLoader) { adapter.restoreState(bundle, classLoader); } @Override public Parcelable saveState() { return adapter.saveState(); } @Override public void startUpdate(ViewGroup container) { adapter.startUpdate(container); } /* * End delegation */ private void debug(String message) { if (DEBUG) { Log.d(TAG, message); } } }
能夠看到在代碼中還存在着 BaseSliderAdapter
另外一個 PagerAdapter ,這是一個正常的PagerAdapter,它既是數據的真正載體同時也起着維護viewpager真正個數的做用。
但用這個方法實現的無限輪播存在着一個很大的缺陷,在 page 頁少於3個的狀況下會出現問題,這是因爲ViewPager自己的機制致使的。
簡單來講,ViewPager在顯示的時候會同時存在3個page頁,當前顯示頁,當前顯示的前一頁,當前顯示的後一頁。當咱們輪播到下一頁時,原來的前一頁會被回收,原來的當前頁變成前一頁,原來的後一頁變成當前頁,同時會加載出新的一頁做爲後一頁。
而在無限輪播小於等於3頁時,因爲前一頁可能沒有被回收就被當作新的一頁加載到後一頁中,這就致使了view重複被ViewGroup添加,而在Android中View只能被容許擁有一個ParentView,這裏就出現了問題。
因此在page頁少於等於3頁的時候仍是要使用基礎的 PagerAdapter。
指示器能夠經過繼承 ViewPager.OnPageChangeListener
與ViewPager保持聯動,其監聽器包括如下方法:
@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // 滑動時的參數變化 } @Override public void onPageSelected(int position) { // 滑動到第幾頁 } @Override public void onPageScrollStateChanged(int state) { // 滑動時的狀態變化 }
剩下的就是看你怎麼定義指示器的界面,附上指示器演示圖和一個自定義的指示器代碼
public class CirclePageIndicator extends View implements PageIndicator { private static final int INVALID_POINTER = -1; private float mRadius; private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG); private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG); private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG); private ViewPager mViewPager; private ViewPager.OnPageChangeListener mListener; private int mCurrentPage; private int mSnapPage; private float mPageOffset; private int mScrollState; private int mOrientation; private boolean mCentered; private boolean mSnap; private int mTouchSlop; private float mLastMotionX = -1; private int mActivePointerId = INVALID_POINTER; private boolean mIsDragging; public CirclePageIndicator(Context context) { this(context, null); } public CirclePageIndicator(Context context, AttributeSet attrs) { this(context, attrs, R.attr.vpiCirclePageIndicatorStyle); } public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); if (isInEditMode()) return; //Load defaults from resources final Resources res = getResources(); final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color); final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color); final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation); final int defaultStrokeColor = res.getColor(R.color.default_circle_indicator_stroke_color); final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width); final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius); final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered); final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap); //Retrieve styles attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0); mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered); mOrientation = a.getInt(R.styleable.CirclePageIndicator_android_orientation, defaultOrientation); mPaintPageFill.setStyle(Style.FILL); mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor)); mPaintStroke.setStyle(Style.STROKE); mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor)); mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth)); mPaintFill.setStyle(Style.FILL); mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_fillColor, defaultFillColor)); mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius); mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap); Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background); if (background != null) { setBackgroundDrawable(background); } a.recycle(); final ViewConfiguration configuration = ViewConfiguration.get(context); mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration); } public void setCentered(boolean centered) { mCentered = centered; invalidate(); } public boolean isCentered() { return mCentered; } public void setPageColor(int pageColor) { mPaintPageFill.setColor(pageColor); invalidate(); } public int getPageColor() { return mPaintPageFill.getColor(); } public void setFillColor(int fillColor) { mPaintFill.setColor(fillColor); invalidate(); } public int getFillColor() { return mPaintFill.getColor(); } public void setOrientation(int orientation) { switch (orientation) { case HORIZONTAL: case VERTICAL: mOrientation = orientation; requestLayout(); break; default: throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL."); } } public int getOrientation() { return mOrientation; } public void setStrokeColor(int strokeColor) { mPaintStroke.setColor(strokeColor); invalidate(); } public int getStrokeColor() { return mPaintStroke.getColor(); } public void setStrokeWidth(float strokeWidth) { mPaintStroke.setStrokeWidth(strokeWidth); invalidate(); } public float getStrokeWidth() { return mPaintStroke.getStrokeWidth(); } public void setRadius(float radius) { mRadius = radius; invalidate(); } public float getRadius() { return mRadius; } public void setSnap(boolean snap) { mSnap = snap; invalidate(); } public boolean isSnap() { return mSnap; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mViewPager == null) { return; } int count = mViewPager.getAdapter().getCount(); if (mViewPager.getAdapter() instanceof InfinitePagerAdapter) { count = ((InfinitePagerAdapter) mViewPager.getAdapter()).getRealCount(); mCurrentPage = mCurrentPage % count; } if (count == 0) { return; } if (mCurrentPage >= count) { setCurrentItem(count - 1); return; } int longSize; int longPaddingBefore; int longPaddingAfter; int shortPaddingBefore; if (mOrientation == HORIZONTAL) { longSize = getWidth(); longPaddingBefore = getPaddingLeft(); longPaddingAfter = getPaddingRight(); shortPaddingBefore = getPaddingTop(); } else { longSize = getHeight(); longPaddingBefore = getPaddingTop(); longPaddingAfter = getPaddingBottom(); shortPaddingBefore = getPaddingLeft(); } final float threeRadius = mRadius * 3; final float shortOffset = shortPaddingBefore + mRadius; float longOffset = longPaddingBefore + mRadius; if (mCentered) { longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius-mRadius) / 2.0f); } float dX; float dY; float pageFillRadius = mRadius; if (mPaintStroke.getStrokeWidth() > 0) { pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f; } //Draw stroked circles for (int iLoop = 0; iLoop < count; iLoop++) { float drawLong = longOffset + (iLoop * threeRadius); if (mOrientation == HORIZONTAL) { dX = drawLong; dY = shortOffset; } else { dX = shortOffset; dY = drawLong; } // Only paint fill if not completely transparent if (mPaintPageFill.getAlpha() > 0) { canvas.drawCircle(dX, dY, pageFillRadius, mPaintPageFill); } // Only paint stroke if a stroke width was non-zero if (pageFillRadius != mRadius) { canvas.drawCircle(dX, dY, mRadius, mPaintStroke); } } //Draw the filled circle according to the current scroll float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius; if (!mSnap && mCurrentPage < count - 1) { cx += mPageOffset * threeRadius; } if (mOrientation == HORIZONTAL) { dX = longOffset + cx; dY = shortOffset; } else { dX = shortOffset; dY = longOffset + cx; } canvas.drawCircle(dX, dY, mRadius, mPaintFill); } @Override public boolean onTouchEvent(MotionEvent ev) { if (super.onTouchEvent(ev)) { return true; } if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) { return false; } final int action = ev.getAction() & MotionEventCompat.ACTION_MASK; switch (action) { case MotionEvent.ACTION_DOWN: mActivePointerId = MotionEventCompat.getPointerId(ev, 0); mLastMotionX = ev.getX(); break; case MotionEvent.ACTION_MOVE: { final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId); final float x = MotionEventCompat.getX(ev, activePointerIndex); final float deltaX = x - mLastMotionX; if (!mIsDragging) { if (Math.abs(deltaX) > mTouchSlop) { mIsDragging = true; } } if (mIsDragging) { mLastMotionX = x; if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) { mViewPager.fakeDragBy(deltaX); } } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: if (!mIsDragging) { int count = mViewPager.getAdapter().getCount(); if (mViewPager.getAdapter() instanceof InfinitePagerAdapter) { count = ((InfinitePagerAdapter) mViewPager.getAdapter()).getRealCount(); } final int width = getWidth(); final float halfWidth = width / 2f; final float sixthWidth = width / 6f; if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) { if (action != MotionEvent.ACTION_CANCEL) { mViewPager.setCurrentItem(mCurrentPage - 1); } return true; } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) { if (action != MotionEvent.ACTION_CANCEL) { mViewPager.setCurrentItem(mCurrentPage + 1); } return true; } } mIsDragging = false; mActivePointerId = INVALID_POINTER; if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag(); break; case MotionEventCompat.ACTION_POINTER_DOWN: { final int index = MotionEventCompat.getActionIndex(ev); mLastMotionX = MotionEventCompat.getX(ev, index); mActivePointerId = MotionEventCompat.getPointerId(ev, index); break; } case MotionEventCompat.ACTION_POINTER_UP: final int pointerIndex = MotionEventCompat.getActionIndex(ev); final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); if (pointerId == mActivePointerId) { final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); } mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId)); break; } return true; } @Override public void setViewPager(ViewPager view) { if (mViewPager == view) { return; } if (view.getAdapter() == null) { throw new IllegalStateException("ViewPager does not have adapter instance."); } mViewPager = view; mViewPager.addOnPageChangeListener(this); invalidate(); } @Override public void setViewPager(ViewPager view, int initialPosition) { setViewPager(view); setCurrentItem(initialPosition); } @Override public void setCurrentItem(int item) { if (mViewPager == null) { throw new IllegalStateException("ViewPager has not been bound."); } mViewPager.setCurrentItem(item); mCurrentPage = item; invalidate(); } @Override 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) { if (mViewPager.getAdapter() instanceof InfinitePagerAdapter) { position = position % ((InfinitePagerAdapter) mViewPager.getAdapter()).getRealCount(); } mCurrentPage = position; mPageOffset = positionOffset; invalidate(); if (mListener != null) { mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } } @Override public void onPageSelected(int position) { if (mViewPager.getAdapter() instanceof InfinitePagerAdapter) { position = position % ((InfinitePagerAdapter) mViewPager.getAdapter()).getRealCount(); } if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) { mCurrentPage = position; mSnapPage = position; invalidate(); } if (mListener != null) { mListener.onPageSelected(position); } } @Override public void addOnPageChangeListener(ViewPager.OnPageChangeListener listener) { mListener = listener; } /* * (non-Javadoc) * * @see android.view.View#onMeasure(int, int) */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == HORIZONTAL) { setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec)); } else { setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec)); } } /** * Determines the width of this view * * @param measureSpec A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */ private int measureLong(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) { //We were told how big to be result = specSize; } else { //Calculate the width according the views count int count = mViewPager.getAdapter().getCount(); if (mViewPager.getAdapter() instanceof InfinitePagerAdapter) { count = ((InfinitePagerAdapter) mViewPager.getAdapter()).getRealCount(); } result = (int) (getPaddingLeft() + getPaddingRight() + (count * 2 * mRadius) + (count - 1) * mRadius + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * Determines the height of this view * * @param measureSpec A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */ private int measureShort(int measureSpec) { int result; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { //We were told how big to be result = specSize; } else { //Measure the height result = (int) (2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } @Override public void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState) state; super.onRestoreInstanceState(savedState.getSuperState()); mCurrentPage = savedState.currentPage; mSnapPage = 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); } @SuppressWarnings("UnusedDeclaration") 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]; } }; } }
ViewPager有個方法叫作setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer)
用於設置ViewPager切換時的動畫效果
但注意這隻能在3.0及其之後使用。由於View的動畫使用的是屬性動畫,而屬性動畫是3.0才推出。固然這個問題能夠克服,首先先使用nineoldandroids
讓動畫在3.0以前也能跑起來,而後再去修改ViewPager的源碼
public void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) { if (Build.VERSION.SDK_INT >= 11) { final boolean hasTransformer = transformer != null; final boolean needsPopulate = hasTransformer != (mPageTransformer != null); mPageTransformer = transformer; setChildrenDrawingOrderEnabledCompat(hasTransformer); if (hasTransformer) { mDrawingOrder = reverseDrawingOrder ? DRAW_ORDER_REVERSE : DRAW_ORDER_FORWARD; } else { mDrawingOrder = DRAW_ORDER_DEFAULT; } if (needsPopulate) populate(); } }
去除if (Build.VERSION.SDK_INT >= 11)
這個if判斷就好了。
全部的PageTransformer都要繼承ViewPager.PageTransformer
接口,其中包含的方法只有一個
@Override public void transformPage(View view, float position) { }
其中position反映的是view的位置變化。
假設如今ViewPager在A頁如今滑出B頁,則:
A頁的position變化就是( 0, -1]
B頁的position變化就是[ 1 , 0 ]
根據這個position就能夠作出多樣的轉場變化了。
一樣要利用 ViewPager.OnPageChangeListener
監聽ViewPager的變化以實現每一個界面的變化。
Animation接口
public interface OnAnimationListener { void onNextAnimationStart(BaseSliderView slider); void onNextAnimationEnd(BaseSliderView slider); void onPreAnimationStart(BaseSliderView slider); void onPreAnimationEnd(BaseSliderView slider); }
監聽變化
/** * A {@link ViewPager} that allows define custom animation */ public class AnimationViewPager extends ViewPager { private int position = 0, prePositon = 0; private OnAnimationListener animationListener; private BaseSliderView slider, preSlider; private boolean animating = false; public AnimationViewPager(Context context) { super(context); initViewPager(); } public AnimationViewPager(Context context, AttributeSet attrs) { super(context, attrs); initViewPager(); } private void initViewPager() { addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (position == 0 && positionOffset == 0) { animateSliderEnd(position); if (slider != null) animationListener.onNextAnimationEnd(slider); } } @Override public void onPageSelected(int position) { prePositon = AnimationViewPager.this.position; AnimationViewPager.this.position = position; if (prePositon > position) animateSliderStart(position, position + 1); if (prePositon < position) animateSliderStart(position, position - 1); } @Override public void onPageScrollStateChanged(int state) { if (state == SCROLL_STATE_IDLE) { animateSliderEnd(position); } } }); } private void animateSliderStart(int position, int prePositon) { if (animationListener == null) return; BaseSliderView slider = null, preSlider = null; if (getAdapter() instanceof InfinitePagerAdapter) { InfinitePagerAdapter pagerAdapter = (InfinitePagerAdapter) getAdapter(); slider = pagerAdapter.getSliderView(position); preSlider = pagerAdapter.getSliderView(prePositon); } else if (getAdapter() instanceof BaseSliderAdapter) { BaseSliderAdapter sliderAdapter = (BaseSliderAdapter) getAdapter(); slider = sliderAdapter.getSliderView(position); preSlider = sliderAdapter.getSliderView(prePositon); } if (slider != null) animationListener.onNextAnimationStart(slider); if (preSlider != null) animationListener.onPreAnimationStart(preSlider); } private void animateSliderEnd(int position) { if (animationListener == null) return; if (getAdapter() instanceof InfinitePagerAdapter) { InfinitePagerAdapter pagerAdapter = (InfinitePagerAdapter) getAdapter(); if (slider == null) slider = pagerAdapter.getSliderView(position); else if (slider != pagerAdapter.getSliderView(position)) { preSlider = slider; slider = pagerAdapter.getSliderView(position); } } else if (getAdapter() instanceof BaseSliderAdapter) { BaseSliderAdapter sliderAdapter = (BaseSliderAdapter) getAdapter(); if (slider == null) slider = sliderAdapter.getSliderView(position); else if (slider != sliderAdapter.getSliderView(position)) { preSlider = slider; slider = sliderAdapter.getSliderView(position); } } if (slider != null) animationListener.onNextAnimationEnd(slider); if (preSlider != null) animationListener.onPreAnimationEnd(preSlider); animating = false; } public OnAnimationListener getAnimationListener() { return animationListener; } public void setAnimationListener(OnAnimationListener animationListener) { this.animationListener = animationListener; } }
繼承OnAnimationListener接口實現後的例子
public class DefaultDescriptionAnimation implements OnAnimationListener { private final long DURATION = 300; @Override public void onNextAnimationStart(BaseSliderView slider) { Log.d("simpleSlider", "onNextAnimationStart:" + slider.getPageTitle()); } @Override public void onNextAnimationEnd(BaseSliderView slider) { Log.d("simpleSlider", "onNextAnimationEnd:" + slider.getPageTitle()); DescriptionSliderView sliderView = (DescriptionSliderView) slider; if (sliderView.getTitleLayout().getVisibility() != View.VISIBLE) translateShowAnimate(sliderView.getTitleLayout()); } @Override public void onPreAnimationStart(BaseSliderView slider) { Log.d("simpleSlider", "onPreAnimationStart:" + slider.getPageTitle()); } @Override public void onPreAnimationEnd(BaseSliderView slider) { Log.d("simpleSlider", "onPreAnimationEnd:" + slider.getPageTitle()); DescriptionSliderView sliderView = (DescriptionSliderView) slider; alphaHideAnimate(sliderView.getTitleLayout()); } public void alphaHideAnimate(View v) { v.clearAnimation(); v.setVisibility(View.INVISIBLE); AlphaAnimation aa = new AlphaAnimation(1, 0); aa.setDuration(DURATION); v.startAnimation(aa); } public void translateShowAnimate(View v) { v.setVisibility(View.VISIBLE); v.clearAnimation(); TranslateAnimation ta = new TranslateAnimation(0, 0, v.getHeight(), 0); ta.setDuration(DURATION); v.startAnimation(ta); } }
今天的ViewPager的介紹就到這了,若你們有問題或者想要在Android上交流能夠大膽的聯繫我!