packagecom.xu81.testflip;importjava.util.Vector;importandroid.content.Context;importandroid.util.AttributeSet;importandroid.view.MotionEvent;importandroid.view.VelocityTracker;importandroid.view.View;importandroid.view.ViewConfiguration;importandroid.view.ViewGroup;importandroid.widget.Scroller;public class ScrollLayout extendsViewGroup {privateScroller mScroller;privateVelocityTracker mVelocityTracker;private intmCurScreen;private int mDefaultScreen = 0;private static final int TOUCH_STATE_REST = 0;private static final int TOUCH_STATE_SCROLLING = 1;private static final int SNAP_VELOCITY = 500;private int mTouchState =TOUCH_STATE_REST;private intmTouchSlop;private floatmLastMotionX;private int sensitivity = 30;private booleanspring;private Vectorlisteners;publicScrollLayout(Context context, AttributeSet attrs) {super(context, attrs);//TODO Auto-generated constructor stub
mScroller = newScroller(context);
mCurScreen=mDefaultScreen;
mTouchSlop=ViewConfiguration.get(getContext()).getScaledTouchSlop();
listeners= new Vector();
}public voidaddChangeListener(LayoutChangeListener listener) {
listeners.add(listener);
}
@Overrideprotected void onLayout(boolean changed, int l, int t, int r, intb) {//TODO Auto-generated method stub
int childLeft = 0;final int childCount =getChildCount();for (int i = 0; i < childCount; i++) {final View childView =getChildAt(i);if (childView.getVisibility() !=View.GONE) {final int childWidth =childView.getMeasuredWidth();
childView.layout(childLeft,0, childLeft +childWidth,
childView.getMeasuredHeight());
childLeft+=childWidth;
}
}
}
@Overrideprotected void onMeasure(int widthMeasureSpec, intheightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);final int width =MeasureSpec.getSize(widthMeasureSpec);final int widthMode =MeasureSpec.getMode(widthMeasureSpec);if (widthMode !=MeasureSpec.EXACTLY) {throw newIllegalStateException("ScrollLayout only canmCurScreen run at EXACTLY mode!");
}final int heightMode =MeasureSpec.getMode(heightMeasureSpec);if (heightMode !=MeasureSpec.EXACTLY) {throw newIllegalStateException("ScrollLayout only can run at EXACTLY mode!");
}//The children are given the same width and height as the scrollLayout
final int count =getChildCount();for (int i = 0; i < count; i++) {
getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
}
scrollTo(mCurScreen* width, 0);
}public voidsnapToDestination() {final int screenWidth =getWidth();final int destScreen = (getScrollX() + screenWidth / 2) /screenWidth;
snapToScreen(destScreen);
}public void snapToScreen(intwhichScreen) {//get the valid layout page
int lastIndex =mCurScreen;
whichScreen= Math.max(0, Math.min(whichScreen, getChildCount() - 1));if (getScrollX() != (whichScreen *getWidth())) {final int delta = whichScreen * getWidth() -getScrollX();
mScroller.startScroll(getScrollX(),0, delta, 0,
Math.abs(delta)* 2);
mCurScreen=whichScreen;
invalidate();//Redraw the layout
}for(LayoutChangeListener listener : listeners)
listener.doChange(lastIndex, whichScreen);
}public void setToScreen(intwhichScreen) {
whichScreen= Math.max(0, Math.min(whichScreen, getChildCount() - 1));
mCurScreen=whichScreen;
scrollTo(whichScreen* getWidth(), 0);
}public intgetCurScreen() {returnmCurScreen;
}
@Overridepublic voidcomputeScroll() {//TODO Auto-generated method stub
if(mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}public booleanisSpring() {returnspring;
}public void setSpring(booleanspring) {this.spring =spring;
}
@Overridepublic booleanonTouchEvent(MotionEvent event) {//TODO Auto-generated method stub
if (mVelocityTracker == null)
mVelocityTracker=VelocityTracker.obtain();
mVelocityTracker.addMovement(event);final int action =event.getAction();final float x =event.getX();switch(action) {caseMotionEvent.ACTION_DOWN:if (!mScroller.isFinished())
mScroller.abortAnimation();
mLastMotionX=x;break;caseMotionEvent.ACTION_MOVE:int deltaX = (int) (mLastMotionX -x);if (Math.abs(deltaX) >sensitivity) {//左滑动为正数、右为负数
if(spring) {
scrollBy(deltaX,0);
mLastMotionX=x;
}else{final int childCount =getChildCount();boolean max = mCurScreen < childCount - 1;boolean min = mCurScreen > 0;boolean canMove = deltaX > 0 ? (max ? true : false)
: (min? true : false);if(canMove) {
scrollBy(deltaX,0);
mLastMotionX=x;
}
}
}break;caseMotionEvent.ACTION_UP:final VelocityTracker velocityTracker =mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000);int velocityX = (int) velocityTracker.getXVelocity();if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {//Fling enough to move left
snapToScreen(mCurScreen - 1);
}else if (velocityX < -SNAP_VELOCITY&& mCurScreen < getChildCount() - 1) {//Fling enough to move right
snapToScreen(mCurScreen + 1);
}else{
snapToDestination();
}if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker= null;
}
mTouchState=TOUCH_STATE_REST;break;caseMotionEvent.ACTION_CANCEL:
mTouchState=TOUCH_STATE_REST;break;
}return true;
}
@Overridepublic booleanonInterceptTouchEvent(MotionEvent ev) {//TODO Auto-generated method stub
final int action =ev.getAction();if ((action ==MotionEvent.ACTION_MOVE)&& (mTouchState !=TOUCH_STATE_REST))return true;final float x =ev.getX();switch(action) {caseMotionEvent.ACTION_MOVE:final int xDiff = (int) Math.abs(mLastMotionX -x);if (xDiff >mTouchSlop)
mTouchState=TOUCH_STATE_SCROLLING;break;caseMotionEvent.ACTION_DOWN:
mLastMotionX=x;
mTouchState= mScroller.isFinished() ?TOUCH_STATE_REST
: TOUCH_STATE_SCROLLING;break;caseMotionEvent.ACTION_CANCEL:caseMotionEvent.ACTION_UP:
mTouchState=TOUCH_STATE_REST;break;
}return mTouchState !=TOUCH_STATE_REST;
}
}