花了几个小时,搞了一个自定义ViewPager雏形。
没有内存管理,没有封装对外的接口。
以后有时间再慢慢丰满,当是一个记录。
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.Scroller;
public class CustomViewPager extends FrameLayout {
private float mFlingSlop;//min fling threshold
private float mDownX;
private float mLastX;
private Scroller mScroller;//used to move child view smoothly
private VelocityTracker mTracker;//calculate the velocity when up key is pressed
private int mCurrentPage = 0;//record the current page
private boolean mHitBound = false;//if at first or last page
private int mChildCount = 0;//child view count
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context, new DecelerateInterpolator(2));
mFlingSlop = ViewConfiguration.get(context).getScaledMinimumFlingVelocity() * 100 / 4;//this value may not proper, but currently used
}
@Override
public void onLayout(boolean changed, int l, int t, int r, int b) {
mChildCount = getChildCount();
int w = r - l;
for (int i = 0; i < mChildCount; i++) {
View view = getChildAt(i);
view.layout(i * w, t, (i + 1) * w, b);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {//clear the scroller effect to make touch fluent
mScroller.abortAnimation();
mScroller.forceFinished(true);
}
mHitBound = false;
mLastX = event.getX();
mDownX = mLastX;
if (mTracker == null) {
mTracker = VelocityTracker.obtain();
}
mTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
int scrollX = getScrollX();
float dx = (mLastX - event.getX());
if (scrollX + dx <= 0) {//first page hit
scrollTo(0, 0);
mHitBound = true;
return false;
} else if (scrollX + dx >= getWidth() * (mChildCount - 1)) {//last page hit
scrollTo(getWidth() * (mChildCount - 1), 0);
mHitBound = true;
return false;
} else {
mTracker.addMovement(event);
scrollBy((int) dx, 0);
}
mLastX = event.getX();
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mHitBound) {// when hit bound, release VelocityTracker
releaseTracker();
return false;
}
int deltaX = 0;
int deltaY = 0;
int rest = getScrollX() % getWidth();//scroll offset in page
int direction = event.getX() - mDownX > 0 ? -1 : 1; // 1 forward, -1 backward;
int toNext = 0;
int sX = Math.abs((getScrollX() - getWidth() * mCurrentPage) % getWidth());
if (sX >= getWidth() / 2f) {//when move over half page, move to next page
toNext |= 1;
} else {
toNext |= 0;
}
mTracker.computeCurrentVelocity(1000);
float velocity = Math.abs(mTracker.getXVelocity());
if (velocity >= mFlingSlop) {//when move fast enough, move to next page
toNext |= 1;
} else {
toNext |= 0;
}
if (toNext == 1) {// next page
if (direction == 1) {// forward
deltaX = getWidth() - rest;
mCurrentPage++;
} else {// backward
deltaX = -rest;
mCurrentPage--;
}
} else {
if (direction == 1) {{// forward
deltaX = -rest;
} else {// backward
deltaX = getWidth() - rest;
}
}
mScroller.startScroll(getScrollX(), getScrollY(), deltaX, deltaY, 500);
invalidate();
releaseTracker();
break;
default:
break;
}
return true;
}
private void releaseTracker() {
if (mTracker != null) {
mTracker.clear();
mTracker.recycle();
mTracker = null;
}
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {//when implement mScroller.startScroll(), this will return true
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
} else {
super.computeScroll();
}
}
}