您好,登錄后才能下訂單哦!
我這一次講使用scroll實現彈性滑動,我不會只有一個例子就說完,因為寫文章的時候我也在學習,我分幾次講完吧。
首先上一段代碼,
private void smoothScrollByScroller(int dy){ mScroller.startScroll(0,dy,0,dy*-1,1000); invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } }
這段代碼是實現彈性滑動的核心,第一個函數指的是緩慢滑動的意思,但是卻沒有這個滑動的實際功能。
startScroll這函數的五個參數指的是起點x坐標,起點y坐標,x位移量,y位移量,這段滑動的時間。這個函數的內部是不斷計算在滑動時間里x和y坐標應該是什么值,然后因為invalidate會調用computeScroll,這個computeScrollOffset函數是判斷當前滑動是否結束,如果沒有結束通過getCurrX和getCurry獲得startScroll函數計算的值,在使用scrollTo滑動相應的位置,因為startScroll會運算很多次,也就是將滑動時間分成很多段,相應的坐標也都算出來,跟著給scrollTo去實現滑動。
這很像是ValueAmition,將時間分成很多段,然后計算相應的值,同時分很多次去實現。
我貼一個類似QQ消息列表的常見的彈性滑動,這里下拉是沒有刷新的,
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } public final class PullView extends ViewGroup { private int mLastY; private Context mContext; private Scroller mScroller; //子View的個數 private int mChildCount; public PullView(Context context){ this(context,null); } public PullView(Context context, AttributeSet attributeSet){ super(context,attributeSet); mContext=context; initView(); } private void initView(){ mScroller=new Scroller(mContext); } @Override public boolean onTouchEvent(MotionEvent event) { int y=(int)event.getY(); switch (event.getAction()){ //手指按下時,初始化按下位置的X,Y位置值 case MotionEvent.ACTION_DOWN: mLastY=y; break; //計算滑動的偏移量,產生滑動效果 case MotionEvent.ACTION_MOVE: //手指向下滑動delayY>0,向上滑動delayY<0 int delayY=y-mLastY; delayY=delayY*-1; scrollBy(0,delayY); break; case MotionEvent.ACTION_UP: /** * scrollY是指:View的上邊緣和View內容的上邊緣(其實就是第一個ChildView的上邊緣)的距離 * scrollY=上邊緣-View內容上邊緣,scrollTo/By方法滑動的知識View的內容 * 往下滑動scrollY是負值 */ int scrollY=getScrollY(); smoothScrollByScroller(scrollY); break; } mLastY=y; return true; } /** * 執行滑動效果 * 使用scroller實現 * @param dy */ private void smoothScrollByScroller(int dy){ mScroller.startScroll(0,dy,0,dy*-1,1000); invalidate(); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } /** * 重新計算子View的高度和寬度 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int measuredWidth; int measureHeight; mChildCount = getChildCount(); //測量子View measureChildren(widthMeasureSpec, heightMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int widthSpaceMode = MeasureSpec.getMode(widthMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); int heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec); //獲取橫向的padding值 int paddingLeft=getPaddingLeft(); int paddingRight=getPaddingRight(); final View childView = getChildAt(0); /** * 如果子View的數量是0,就讀取LayoutParams中數據 * 否則就對子View進行測量 * 此處主要是針對wrap_content這種模式進行處理,因為默認情況下 * wrap_content等于match_parent */ if (mChildCount == 0) { ViewGroup.LayoutParams layoutParams=getLayoutParams(); if(layoutParams!=null){ setMeasuredDimension(layoutParams.width,layoutParams.height); }else { setMeasuredDimension(0, 0); } } else if (heightSpaceMode == MeasureSpec.AT_MOST && widthSpaceMode == MeasureSpec.AT_MOST) { measuredWidth = childView.getMeasuredWidth() * mChildCount; measureHeight = getChildMaxHeight(); //將兩側的padding值加上去 measuredWidth=paddingLeft+measuredWidth+paddingRight; setMeasuredDimension(measuredWidth, measureHeight); } else if (heightSpaceMode == MeasureSpec.AT_MOST) { measureHeight = getChildMaxHeight(); setMeasuredDimension(widthSpaceSize, measureHeight); } else if (widthSpaceMode == MeasureSpec.AT_MOST) { measuredWidth = childView.getMeasuredWidth() * mChildCount; measuredWidth=paddingLeft+measuredWidth+paddingRight; setMeasuredDimension(measuredWidth, heightSpaceSize); } } /** * 獲取子View中最大高度 * @return */ private int getChildMaxHeight(){ int maxHeight=0; for (int i = 0; i < mChildCount; i++) { View childView = getChildAt(i); if (childView.getVisibility() != View.GONE) { int height = childView.getMeasuredHeight(); if(height>maxHeight){ maxHeight=height; } } } return maxHeight; } /** * 設置子View的布局 * @param changed * @param l * @param t * @param r * @param b */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int childLeft = 0; for (int i = 0; i < mChildCount; i++) { View childView = getChildAt(i); if (childView.getVisibility() != View.GONE) { int childWidth = childView.getMeasuredWidth(); childView.layout(childLeft, 0, childLeft + childWidth, childView.getMeasuredHeight()); childLeft += childWidth; } } } } <android.com.listfragment.PullView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <LinearLayout android:layout_width="match_parent" android:layout_height="1500dp" android:background="#806363"></LinearLayout> </android.com.listfragment.PullView>
這里的ViewGroup的繪畫和測量我就不多說,我就說一下它獲取函數,計算坐標的一些事。
它在手指按下時記錄y坐標,在手指移動時,跟著移動子View,在手指抬起時,使用彈性滑動的函數smoothScrollByScroller。
大家會發現為什么一些計算出的坐標要加負號,因為在我們人眼里,我們下拉y坐標的位移量是正的,但是在系統認為這個值是負的,原因我太菜不知道,知道的求大神評論留言告訴。
下一次寫一個隨手指彈性滑動的例子。
以上這篇Android Scroll實現彈性滑動_列表下拉彈性滑動的示例代碼就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。