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

作者:键盘舞者113 时间:2022-02-07 16:01:49 

我这一次讲使用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坐标的位移量是正的,但是在系统认为这个值是负的,原因我太菜不知道,知道的求大神评论留言告诉。

下一次写一个随手指弹性滑动的例子。

来源:http://blog.csdn.net/z979451341/article/details/70245311

标签:Android,Scroll,弹性,滑动,列表下拉
0
投稿

猜你喜欢

  • Android 自定义布局竖向的ViewPager的实现

    2022-12-30 19:56:17
  • Android UI控件ExpandableListView基本用法详解

    2021-12-26 22:20:50
  • Java接口的简单定义与实现方法示例

    2022-11-22 05:04:43
  • c#消息提示框messagebox的详解及使用

    2022-06-25 14:57:44
  • C#使用DLLImport调用外部DLL的方法

    2022-07-17 04:41:18
  • 详解Java中运算符及用法

    2023-11-29 08:17:57
  • java组件commons-fileupload文件上传示例

    2022-08-16 02:42:56
  • C#实现复杂XML的序列化与反序列化

    2023-12-19 05:09:45
  • C#异步调用的好处和方法分享

    2023-04-08 11:10:56
  • C#中的char与string详解

    2023-09-13 07:07:27
  • 通过Java实现文件断点续传功能

    2022-06-22 16:30:42
  • Unity实现虚拟键盘

    2022-05-24 11:25:38
  • C# 中如何利用lambda实现委托事件的挂接

    2022-02-06 03:18:00
  • springboot下ueditor上传功能的实现及遇到的问题

    2023-09-22 05:46:21
  • 详解spring cloud ouath2中的资源服务器

    2022-09-24 15:36:43
  • java线程池使用后到底要关闭吗

    2022-03-17 04:28:43
  • Java实现堆排序和图解

    2023-11-11 12:13:37
  • java如何消除太多的if else判断示例代码

    2023-01-17 21:57:40
  • Java httpClient介绍以及使用示例

    2023-03-15 23:51:15
  • SpringBoot多数据源切换实现代码(Mybaitis)

    2021-11-07 11:15:50
  • asp之家 软件编程 m.aspxhome.com