package com.example.administrator.cookman.ui.component.magicindicator; import android.util.SparseArray; import android.util.SparseBooleanArray; /** * 方便扩展IPagerNavigator的帮助类,将ViewPager的3个回调方法转换成 * onSelected、onDeselected、onEnter等回调,方便扩展 * 博客: http://hackware.lucode.net * Created by hackware on 2016/6/26. */ public class NavigatorHelper { private int mCurrentIndex; private int mTotalCount; private int mScrollState = ScrollState.SCROLL_STATE_IDLE; // 转换后的回调 private OnNavigatorScrollListener mNavigatorScrollListener; // 记录有哪些item处于未选中、未完全leave状态 private SparseBooleanArray mDeselectedItems = new SparseBooleanArray(); private SparseArray<Float> mLeavedPercents = new SparseArray<Float>(); private float mLastPositionOffsetSum; private int mLastIndex; private boolean mSkimOver; public NavigatorHelper() { } public int getSafeIndex(int index) { return Math.max(Math.min(index, mTotalCount - 1), 0); } public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (mNavigatorScrollListener != null) { float currentPositionOffsetSum = position + positionOffset; boolean leftToRight = currentPositionOffsetSum >= mLastPositionOffsetSum; int safePosition = getSafeIndex(position); if (mScrollState != ScrollState.SCROLL_STATE_IDLE) { int enterIndex; int leaveIndex; float enterPercent; float leavePercent; if (leftToRight) { enterIndex = getSafeIndex(position + 1); enterPercent = positionOffset; leaveIndex = safePosition; leavePercent = positionOffset; } else { enterIndex = safePosition; enterPercent = 1.0f - positionOffset; leaveIndex = getSafeIndex(safePosition + 1); leavePercent = 1.0f - positionOffset; } for (int i = 0; i < mTotalCount; i++) { if (i == enterIndex || i == leaveIndex) { continue; } Float leavedPercent = mLeavedPercents.get(i, 0.0f); if (leavedPercent != 1.0f) { mNavigatorScrollListener.onLeave(i, mTotalCount, 1.0f, leftToRight); mLeavedPercents.put(i, 1.0f); } } if (enterIndex == leaveIndex) { if (enterIndex == mTotalCount - 1 && mLeavedPercents.get(enterIndex, 0.0f) != 0.0f && enterPercent == 0.0f && leftToRight) { boolean dispatchEnterEvent = mSkimOver || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || enterIndex == mCurrentIndex; if (dispatchEnterEvent) { mNavigatorScrollListener.onEnter(enterIndex, mTotalCount, 1.0f, true); mLeavedPercents.put(enterIndex, 0.0f); } } return; } if (1.0f - mLeavedPercents.get(enterIndex, 0.0f) != enterPercent) { boolean dispatchEnterEvent = mSkimOver || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || enterIndex == mCurrentIndex; if (dispatchEnterEvent) { mNavigatorScrollListener.onEnter(enterIndex, mTotalCount, enterPercent, leftToRight); mLeavedPercents.put(enterIndex, 1.0f - enterPercent); } } if (mLeavedPercents.get(leaveIndex, 0.0f) != leavePercent) { if (leftToRight && leaveIndex == getCurrentIndex() && leavePercent == 0.0f) { boolean dispatchEnterEvent = mSkimOver || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || leaveIndex == mCurrentIndex; if (dispatchEnterEvent) { mNavigatorScrollListener.onEnter(leaveIndex, mTotalCount, 1.0f, true); mLeavedPercents.put(leaveIndex, 0.0f); } } else { boolean dispatchLeaveEvent = mSkimOver || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || leaveIndex == mLastIndex || (leaveIndex == mCurrentIndex - 1 && mLeavedPercents.get(leaveIndex, 0.0f) != 1.0f) || (leaveIndex == mCurrentIndex + 1 && mLeavedPercents.get(leaveIndex, 0.0f) != 1.0f); if (dispatchLeaveEvent) { mNavigatorScrollListener.onLeave(leaveIndex, mTotalCount, leavePercent, leftToRight); mLeavedPercents.put(leaveIndex, leavePercent); } } } } else { for (int i = 0; i < mTotalCount; i++) { if (i == mCurrentIndex) { continue; } boolean deselected = mDeselectedItems.get(i); if (!deselected) { mNavigatorScrollListener.onDeselected(i, mTotalCount); mDeselectedItems.put(i, true); } Float leavedPercent = mLeavedPercents.get(i, 0.0f); if (leavedPercent != 1.0f) { mNavigatorScrollListener.onLeave(i, mTotalCount, 1.0f, leftToRight); mLeavedPercents.put(i, 1.0f); } } mNavigatorScrollListener.onEnter(mCurrentIndex, mTotalCount, 1.0f, false); mLeavedPercents.put(mCurrentIndex, 0.0f); mNavigatorScrollListener.onSelected(mCurrentIndex, mTotalCount); mDeselectedItems.put(mCurrentIndex, false); } mLastPositionOffsetSum = currentPositionOffsetSum; } } public void onPageSelected(int position) { int currentIndex = setCurrentIndex(position); if (mNavigatorScrollListener != null) { mNavigatorScrollListener.onSelected(currentIndex, mTotalCount); mDeselectedItems.put(currentIndex, false); for (int i = 0, j = mTotalCount; i < j; i++) { if (i == currentIndex) { continue; } boolean deselected = mDeselectedItems.get(i); if (!deselected) { mNavigatorScrollListener.onDeselected(i, mTotalCount); mDeselectedItems.put(i, true); } } } } public void onPageScrollStateChanged(int state) { mScrollState = state; } public int getCurrentIndex() { return getSafeIndex(mCurrentIndex); } private int setCurrentIndex(int currentIndex) { mLastIndex = mCurrentIndex; mCurrentIndex = getSafeIndex(currentIndex); return mCurrentIndex; } public int getTotalCount() { return mTotalCount; } public void setTotalCount(int totalCount) { mTotalCount = totalCount; mDeselectedItems.clear(); mLeavedPercents.clear(); } public int getScrollState() { return mScrollState; } public boolean isSkimOver() { return mSkimOver; } public void setSkimOver(boolean skimOver) { mSkimOver = skimOver; } public OnNavigatorScrollListener getNavigatorScrollListener() { return mNavigatorScrollListener; } public void setNavigatorScrollListener(OnNavigatorScrollListener navigatorScrollListener) { mNavigatorScrollListener = navigatorScrollListener; } public void clear() { mTotalCount = 0; mCurrentIndex = 0; mLastIndex = 0; mLastPositionOffsetSum = 0.0f; mScrollState = ScrollState.SCROLL_STATE_IDLE; mDeselectedItems.clear(); mLeavedPercents.clear(); } public interface OnNavigatorScrollListener { void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight); void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight); void onSelected(int index, int totalCount); void onDeselected(int index, int totalCount); } }