/* * Created by LuaView. * Copyright (c) 2017, Alibaba Group. All rights reserved. * * This source code is licensed under the MIT. * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree. */ package com.taobao.luaview.view.viewpager; import android.content.Context; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import com.taobao.luaview.util.LogUtil; import com.taobao.luaview.view.adapter.LVLoopPagerAdapter; /** * A ViewPager subclass enabling infinte scrolling of the viewPager elements * <p/> * When used for paginating views (in opposite to fragments), no code changes * should be needed only change xml's from <android.support.v4.view.ViewPager> * to <com.imbryk.viewPager.LoopViewPager> * <p/> * If "blinking" can be seen when paginating to first or last view, simply call * seBoundaryCaching( true ), or change DEFAULT_BOUNDARY_CASHING to true * <p/> * When using a FragmentPagerAdapter or FragmentStatePagerAdapter, * additional changes in the adapter must be done. * The adapter must be prepared to create 2 extra items e.g.: * <p/> * The original adapter creates 4 items: [0,1,2,3] * The modified adapter will have to create 6 items [0,1,2,3,4,5] * with mapping realPosition=(position-1)%count * [0->3, 1->0, 2->1, 3->2, 4->3, 5->0] */ public class LoopViewPager extends ViewPager { private OnPageChangeListener mOuterPageChangeListener; private LVLoopPagerAdapter mAdapter; private float mPreviousOffset = -1; private float mPreviousRealPosition = -1; public LoopViewPager(Context context) { super(context); init(); } @Override public void setAdapter(PagerAdapter adapter) { mAdapter = (LVLoopPagerAdapter) adapter; super.setAdapter(mAdapter); setCurrentItem(0, false); } @Override public PagerAdapter getAdapter() { return mAdapter; } public int getRealCount() { return mAdapter != null ? mAdapter.getRealCount() : 0; } public int getCount() { return mAdapter != null ? mAdapter.getCount() : 0; } public void setLooping(boolean looping) { if (mAdapter != null && mAdapter.isLooping() != looping) { final int currentPosition = super.getCurrentItem(); super.setAdapter(null); mAdapter.setLooping(looping); super.setAdapter(mAdapter); if (looping) { super.setCurrentItem(mAdapter.toFakePosition(currentPosition), false); } mPreviousRealPosition = -1; mPreviousOffset = -1; } } public boolean isLooping() { return mAdapter != null && mAdapter.isLooping(); } @Override public int getCurrentItem() { return mAdapter != null ? mAdapter.toRealPosition(super.getCurrentItem()) : super.getCurrentItem(); } @Override public void setCurrentItem(int item) { setCurrentItem(item, false); } public void setCurrentItem(int realItem, boolean smoothScroll) { final int fakeItem = mAdapter.toFakePosition(realItem); final int currentFakeItem = super.getCurrentItem(); // LogUtil.d("yesong", "setCurrentItem", fakeItem, currentFakeItem); if (fakeItem != currentFakeItem) { super.setCurrentItem(fakeItem, smoothScroll); } } @Override public void setOnPageChangeListener(OnPageChangeListener listener) { mOuterPageChangeListener = listener; } private boolean isBoundaryPosition(int position) { return position == 0 || (position == getCount() - 1); } private void init() { super.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int position) { // LogUtil.d("yesong", "onPageSelected", position); if (mAdapter != null && mAdapter.shouldLooping()) { int fakePosition = position; int realPosition = mAdapter.toRealPosition(fakePosition); if (mPreviousRealPosition != realPosition) { mPreviousRealPosition = realPosition; if (mOuterPageChangeListener != null) { mOuterPageChangeListener.onPageSelected(realPosition); } } } else { mPreviousRealPosition = position; if (mOuterPageChangeListener != null) { mOuterPageChangeListener.onPageSelected(position); } } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // LogUtil.d("yesong", "onPageScrolled-offset", position, positionOffset, positionOffsetPixels); if (mAdapter != null && mAdapter.shouldLooping()) { final int fakePosition = position; final int realPosition = mAdapter.toRealPosition(fakePosition); if (positionOffset == 0 && mPreviousOffset == 0 && isBoundaryPosition(fakePosition)) { // LogUtil.d("yesong", "onPageScrolled", fakePosition, realPosition); setCurrentItem(realPosition, false); } mPreviousOffset = positionOffset; if (mOuterPageChangeListener != null) { if (realPosition == mAdapter.getRealCount() - 1) { if (positionOffset > 0.5) { mOuterPageChangeListener.onPageScrolled(0, 0, 0); } else { mOuterPageChangeListener.onPageScrolled(realPosition, 0, 0); } } else { mOuterPageChangeListener.onPageScrolled(realPosition, positionOffset, positionOffsetPixels); } } } else { if (mOuterPageChangeListener != null) { mOuterPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } } } @Override public void onPageScrollStateChanged(int state) { // LogUtil.d("yesong", "onPageScrollStateChanged", state); if (mAdapter != null && mAdapter.shouldLooping()) { int fakePosition = LoopViewPager.super.getCurrentItem(); int realPosition = mAdapter.toRealPosition(fakePosition); if (state == ViewPager.SCROLL_STATE_IDLE && isBoundaryPosition(fakePosition)) { // LogUtil.d("yesong", "onPageScrollStateChanged", fakePosition, realPosition); setCurrentItem(realPosition, false); } } if (mOuterPageChangeListener != null) { mOuterPageChangeListener.onPageScrollStateChanged(state); } } }); } }