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


猜你喜欢
- @Valid:@Valid注解用于校验,所属包为:javax.validation.Valid。① 首先需要在实体类的相应字段上添加用于充当
- 本文实例为大家分享了Android中TabLayout结合ViewPager实现页面切换,供大家参考,具体内容如下一、实现思路1、在buil
- 本文实例为大家分享了Java实现宠物商店管理的具体代码,供大家参考,具体内容如下第一种实现方式:抽象类和对象数组public abstrac
- 最近项目中使用springboot+jwt实现登录权限控制,所以在这里记录一下防止以后忘记,毕竟好记性不如烂笔头嘛~。首先我们需要导入使用到
- springmvc常用注解,操作传入参数@RequestParam一般用于jsp参数名和后台方法参数指定,对应/*  
- 参考文章图解Java中插入排序算法的原理与实现实现效果示例代码import java.awt.*;public class AlgoVisu
- Android调试出现The selected device is incompatible问题解决在做Android调试时碰到该问题。详情
- 一、为何要使用netty开发由于之前已经用Java中的socket写过一版简单的聊天室,这里就不再对聊天室的具体架构进行细致的介绍了,主要关
- 一个线程如何知道另一线程已经结束?Thread类提供了回答此问题的方法。有两种方法可以判定一个线程是否结束。第一,可以在线程中调用isAli
- 题目:企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按10
- 在使用IDEA写代码的时候,打开tabs都挤在一行,当打开页面过多的时候,前面的页面无法直观看到,非常不方便。通过简单设置就可以实现tabs
- 一、背景当前B/S模式已成为应用开发的主流,而在企业办公系统中,常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统、银行系
- 本文实例为大家分享了如何利用AOP实现SqlSugar自动事务,供大家参考,具体内容如下先看一下效果,带接口层的三层架构:BL层: publ
- 场景日常开发,if-else语句写的不少吧??当逻辑分支非常多的时候,if-else套了一层又一层,虽然业务功能倒是实现了,但是看起来是真的
- 我用的是Eclipse打包,但在CMD窗口执行的时候报“ActiveMQ.jar中没有主清单属性”错误。在网上搜了下,这个与MANIFEST
- Android中可以创建三种对话框、确定取消对话框、单选对话框、多选对话框android中的确定取消对话框演示示例Android中使用单选对
- 在value目录下,创建styles.xml文件<?xml version="1.0" encoding=&quo
- C#事件使用+= -=使用起来是很方便的,但是却不能整体清空所有事件。比如一个常见的操作,打开界面注册监听事件,关闭界面需要把所有的事件清空
- 题目:求100之内的素数方法一:package airthmatic;public class demo8 { /** * 素数是指因数只有
- 本文以实例介绍了C#如何通过winmm.dll来播放声音,主要实现步骤如下:1.首先导入如下两个函数:/// <summary>