首页 > 系统 > Android > 正文

Android Scroll实现弹性滑动_列表下拉弹性滑动的示例代码

2019-10-22 18:16:44
字体:
来源:转载
供稿:网友

我这一次讲使用scroll实现弹性滑动,我不会只有一个例子就说完,因为写文章的时候我也在学习,我分几次讲完吧。

首先上一段代码,

private void smoothScrollByScroller(int dy){ mScroller.startScroll(0,dy,0,dy*-1,1000); invalidate();}@Overridepublic 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实现弹性滑动_列表下拉弹性滑动的示例代码就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表