When I learned the workspace class and came into contact with scroller, I began to be confused. In viewgroup
Scrollto (int x, int y); scrollby (int x, int y); getscrollx (); getscrolly
(); And other methods. Isn't it possible to implement rolling,
Why should I add a scroroller in it? What is the association between scroroller. startscroll and scrollto?
What is the difference between getscrollx () and scroller. getcurrx?
With such a question, I found a lot of information on the Internet and did not understand it. I found an instance later,
Block the scroler. startscroll method, and then immediately understand the role of scroroller.
Instance connection: available
Here we also paste the code for ease of viewing:
public class MyScrollLayout extends ViewGroup{ private static final String TAG = "ScrollLayout"; private VelocityTracker mVelocityTracker; private static final int SNAP_VELOCITY = 600; private Scroller mScroller; private int mCurScreen; private int mDefaultScreen = 0; private float mLastMotionX; // private int mTouchSlop; private OnViewChangeListener mOnViewChangeListener; public MyScrollLayout(Context context) {super(context);// TODO Auto-generated constructor stubinit(context);}public MyScrollLayout(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stubinit(context);}public MyScrollLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stubinit(context);}private void init(Context context){mCurScreen = mDefaultScreen; mScroller = new Scroller(context); }@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {Log.d("switchView","MyScrollLayout onLayout");// TODO Auto-generated method stub if (changed) { 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, int heightMeasureSpec) {Log.d("switchView","MyScrollLayout onMeasure");// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);final int width = MeasureSpec.getSize(widthMeasureSpec); final int widthMode = MeasureSpec.getMode(widthMeasureSpec); final int count = getChildCount(); for (int i = 0; i < count; i++) { getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } scrollTo(mCurScreen * width, 0);} public void snapToDestination() { final int screenWidth = getWidth(); final int destScreen = (getScrollX()+ screenWidth/2)/screenWidth; Log.d("switchView","MyScrollLayout snapToDestination"+getScrollX()); snapToScreen(destScreen); } public void snapToScreen(int whichScreen) { // get the valid layout page 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); Log.d("switchView","MyScrollLayout snapToScreen delta="+delta); mCurScreen = whichScreen; invalidate(); // Redraw the layout if (mOnViewChangeListener != null) { mOnViewChangeListener.OnViewChange(mCurScreen); } } } @Overridepublic void computeScroll() {Log.d("switchView","MyScrollLayout computeScroll"+getScrollX());// TODO Auto-generated method stubLog.d("switchView","MyScrollLayout computeScroll mScroller.getCurrX()"+mScroller.getCurrX());if (mScroller.computeScrollOffset()) { Log.d("switchView","MyScrollLayout computeScroll mScroller.getCurrX()"+mScroller.getCurrX()); scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } }@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stub final int action = event.getAction(); final float x = event.getX(); final float y = event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: Log.i("", "onTouchEvent ACTION_DOWN"); if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(event); } if (!mScroller.isFinished()){ mScroller.abortAnimation(); } mLastMotionX = x; break; case MotionEvent.ACTION_MOVE: int deltaX = (int)(mLastMotionX - x); Log.d("switchView","MyScrollLayout onTouchEvent"+mLastMotionX+";x="+x); if (IsCanMove(deltaX)) { if (mVelocityTracker != null) { mVelocityTracker.addMovement(event); } mLastMotionX = x; scrollBy(deltaX, 0); } break; case MotionEvent.ACTION_UP: int velocityX = 0; if (mVelocityTracker != null) { mVelocityTracker.addMovement(event); mVelocityTracker.computeCurrentVelocity(1000); velocityX = (int) mVelocityTracker.getXVelocity(); } if (velocityX > SNAP_VELOCITY && mCurScreen > 0) { // Fling enough to move left Log.e(TAG, "snap left"); snapToScreen(mCurScreen - 1); } else if (velocityX < -SNAP_VELOCITY && mCurScreen < getChildCount() - 1) { // Fling enough to move right Log.e(TAG, "snap right"); snapToScreen(mCurScreen + 1); } else { snapToDestination(); } if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } // mTouchState = TOUCH_STATE_REST; break; } return true; }private boolean IsCanMove(int deltaX){if (getScrollX() <= 0 && deltaX < 0 ){return false;}if (getScrollX() >= (getChildCount() - 1) * getWidth() && deltaX > 0){return false;}return true;}public void SetOnViewChangeListener(OnViewChangeListener listener){mOnViewChangeListener = listener;}}
The following method is called after motionevent. action_up. After the motionevent. action_up method is blocked, the screen stops sliding when the finger stops sliding,
It will not automatically jump to the next screen, that is, after the finger leaves the screen, the next scroll is completed by scroller, and the previous scroll
It is completed by scrollby of viewgroup.
mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta)*2);
At this time, the work is not complete. scroller and viewgroup are two independent individuals,
The view will not scroll. You need to manually add code to make it scroll:
public void computeScroll() {// TODO Auto-generated method stubif (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } }
Among them, scrollto is used to make the view scroll with scroller,
Among them, mscroroller. computescroloffset () is not only used to judge whether the rolling is complete,
We also assigned a value to scroler. mcurrx, that is, updating the coordinates of currx in real time during the rolling process,
So scrollto (mscroroller. getcurrx (), mscroroller. getcurry (); you can scroll with scroroller.
View Source Code:
public boolean computeScrollOffset() { if (mFinished) { return false; } int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); if (timePassed < mDuration) { switch (mMode) { case SCROLL_MODE: float x = (float)timePassed * mDurationReciprocal; if (mInterpolator == null) x = viscousFluid(x); else x = mInterpolator.getInterpolation(x); mCurrX = mStartX + Math.round(x * mDeltaX); mCurrY = mStartY + Math.round(x * mDeltaY); break; case FLING_MODE: float timePassedSeconds = timePassed / 1000.0f; float distance = (mVelocity * timePassedSeconds) - (mDeceleration * timePassedSeconds * timePassedSeconds / 2.0f); mCurrX = mStartX + Math.round(distance * mCoeffX); // Pin to mMinX <= mCurrX <= mMaxX mCurrX = Math.min(mCurrX, mMaxX); mCurrX = Math.max(mCurrX, mMinX); mCurrY = mStartY + Math.round(distance * mCoeffY); // Pin to mMinY <= mCurrY <= mMaxY mCurrY = Math.min(mCurrY, mMaxY); mCurrY = Math.max(mCurrY, mMinY); if (mCurrX == mFinalX && mCurrY == mFinalY) { mFinished = true; } break; } } else { mCurrX = mFinalX; mCurrY = mFinalY; mFinished = true; } return true; }
When the coordinates of the view change, the computescroll () method is called to achieve dynamic control of the entire slide.