PullScrollView详解(四)——完全使用listview实现下拉回弹(方法一)

2024-02-28 08:38

本文主要是介绍PullScrollView详解(四)——完全使用listview实现下拉回弹(方法一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在前面三篇中,我为大家展示了使用ScrollView实现下拉回弹的效果。但如果ScrollView里如果嵌套使用ListView就可能会出现问题,因为两者都会有滑动监听。操作起来可能会起冲突,然后解决了冲突问题,到后面页面性能也会很差强人意。即然如此,那我们就直接使用listview来实现下拉回弹的效果就好了。
在这篇中,我先给大家展示一种比较容易出效果的方法——重写overScrollBy()函数。在下一篇中,我们将模仿PullScrollView中的实现方式自己对OnTouchEvent()进行监听、操作。

注意注意!!!!本篇文章讲述的OverScrollBy(),大家应该把最大注意力放在《4、用途:捕捉当前listview是否到底或到顶》部分,至于下拉回弹,大家看看就好,OverScrollBy()实现的下拉回弹,bug一堆,根本无法实际运用到实际项目中,大家看看就好,下篇将带着大家利用OnTouchEvent()实现下拉回弹的效果。

一、setOverScrollMode()与OverScrollBy()
1、OverScrollBy()
OverScrollBy()是Android 9 之后才新增的API. 用于设定listview滚出屏幕后的回弹效果。先看OverScrollBy()函数的定义:

protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) 
它的参数多的有点让人模糊,下面给大家说下各个参数的意思。这些意思目前大家看不懂也没关系,先大致了解下,后面讲例子时还会再讲。
deltaX:当前X轴滑动的像素数
deltaY:当前Y轴滑动的像素数
scrollX:在加上deltaX值以前的X轴总的滑动量
scrollY:在加上deltaY值以前的Y轴总滑动量
scrollRangeX:
scrollRangeY:这两个什么意思,我也没弄懂
maxOverScrollX:X轴最大的OverScroll范围(最大可超过边界的像素)
maxOverscrollY:Y轴最大的OverScroll范围(最大可超过边界的像素)
isTouchEvent:当前overScrollBy函数的调用是否由Touch事件引起的
2、setOverScrollMode()
上面OverScrollBy()是当listview超过顶部或者底部的时候,会被调用。那定义listView能不能超过顶部或底部滑动,也就是说让不让OverScrollBy()调用,是通过setOverScrollMode()函数来定义的。

public void setOverScrollMode(int mode)
mode有三个取值:
//一直允许超过顶部/底部下拉
public static final int OVER_SCROLL_ALWAYS = 0;
//只有Content足够大到能scroll的时候,才允许超过顶部/底部下拉(系统默认值)
public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1;
//不允许超过顶部/底部下拉
public static final int OVER_SCROLL_NEVER = 2;
当然,我们也可以不设置setOverScrollMode(int mode),系统默认的滚动属性为OVER_SCROLL_IF_CONTENT_SCROLLS;即只有listview的content足够大到可以滚动的情况下,才允许超过顶部/底部下拉
这里大家应该对OverScrollBy()有个初步的认识了,下面我们先看看怎么实现下拉回弹,然后再讲解,为什么要这么做。
二、简单示例
先看下效果:

注意,overScrollBy()实现的回弹效果是不能设置下拉方向的,即,不但顶部下拉会回弹,在底部下拉时也会回弹。但从效果图中也可以看到,顶部下拉会回弹,底部下拉是不会回弹的,这是因为在最终代码中做了顶部还是底部判断,当在底部时,就不让用户上拉回弹了,至于怎么做到的,来一起看代码吧。

下面我们就通过一个最简单的例子来看下OverScrollBy()的用法及效果。

1、实现OverScrollView
首先,新建一个类OverScrollView,重写ListView
代码如下:
class OverScrollList extends ListView {
    //定义最大滚动高度
    int mContentMaxMoveHeight = 300;
 
    public OverScrollList(Context context) {
        super(context);
    }
 
    public OverScrollList(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
 
    public OverScrollList(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
 
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
 
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mContentMaxMoveHeight, isTouchEvent);
    }
}

在这个类里面,只做了两件事:
第一:定义一下变量mContentMaxMoveHeight,来表示可滑动到最大高度
int mContentMaxMoveHeight = 300;
第二:重写overScrollBy函数,把return语句中的maxOverScrollY替换成我们定义的mContentMaxMoveHeight;
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
 
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mContentMaxMoveHeight, isTouchEvent);
    }
要实现可以overscroll的listview就需要做这么多,下面就是一如即往的往listview里填充数据的部分了。
2、ListView填充数据
在填充数据前,还是给大家看一下MainActivity的布局:(main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent"
        >
    <com.harvic.OverScrollDemo.OverScrollList
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
</LinearLayout>
下面就是正式填充数据的环节了。

先创建一个XML来做为Item的布局:(item_layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@android:id/text1"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:gravity="center_vertical"
          android:minHeight="40dp"
          android:background="#ffffff"/>
然后就是在MainActivity中的填充数据的部分了,代码如下 :
public class MainActivity extends Activity {
    private String[] mStrings = {"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
            "Allgauer Emmentaler", "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
            "Allgauer Emmentaler"};
    private LinkedList<String> mListItems;
    private OverScrollList mListView;
    private ArrayAdapter<String> mAdapter;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        mListView = (OverScrollList) findViewById(R.id.listview);
        //配置Adapter
        mListItems = new LinkedList<String>();
        mListItems.addAll(Arrays.asList(mStrings));
        mAdapter = new ArrayAdapter<String>(this,R.layout.item_layout, mListItems);
        
        mListView.setAdapter(mAdapter);
 
    }
}
这些都是有关ListView的最基本的部分了,没什么难度,也没什么讲解的必要。
源码在文章底部给出
3、疑问
(1)、为什么在OverScrollList中重写了overScrollBy后,还要设定 super.overScrollBy()里的maxOverScrollY值呢?

答:通过打日志,大家可以看到,overScrollBy里的maxOverScrollY的值一直是0!!!
也就是说,google给我们实现了overScrollBy函数,但需要我们自己设定可overScroll的最大值。不然overScroll的最大值默认是0,即不会上下拉动!!!

(2)、overScrollBy()函数什么时候会调?

答:在listview正常滑动时,overScrollBy()函数是不会被调用的,只有在超出ListView滑动界限时才会被调用。

4、用途:捕捉当前listview是否到底或到顶
现在我们先总结一下:
listview具不具有下拉反弹的功能是靠setOverScrollMode()来设定的。
具有下拉反弹功能以后下拉多少是靠 super.overScrollBy()里的maxOverScrollY值确定的。
overScrollBy()在listview到顶或到底时仍然下拉/上拉时才会被调用。
所以根据上面三点,我们就可以在listview中并不实现下拉回弹的效果时,判断当前Listview是否到顶或到底
(1)、简单计算方法

先列出代码如下:

protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
    if (deltaY>0){
        System.out.println("滑动到底端");
    }else if (deltaY < 0){
        System.out.println("滑动到顶端");
    }
    return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
很简单的原理:
1、首先,不改写super.overScrollBy()中的maxOverScrollY的值。因为maxOverScrollY默认是0,所以不会listview虽具有默认的滑动功能却不会滑动。
2、利用overScrollBy()只有在滑动到顶部、底部且超出滑动区域时,才会被调用的性质。当被overScrollBy调用时,肯定是到了顶部或者底部!!!所以,如果到了顶端,用户向下拉的时候overScrollBy才会被调用。此时手指向下滑动,deltaY必定小于0。同理,当listview到了底部时,只有用户向上拉的时候才会被调用,这时候手指肯定是向上移动的,所以deltaY肯定是大于0的。
deltaY的计算方法是用当前的触摸的手指位置减去上次捕捉到的手指位置。
(2)、系统给出的计算方法
看起来上面的方法好像是万无一失的,(其实我也没发现哪里会有问题),但系统研究了下源码,发现在View.java中的overScrollBy()的实现代码中有这么一段:

protected boolean overScrollBy(int deltaX, int deltaY,
        int scrollX, int scrollY,
        int scrollRangeX, int scrollRangeY,
        int maxOverScrollX, int maxOverScrollY,
        boolean isTouchEvent) {
    
    …………
 
int newScrollX = scrollX + deltaX;
int newScrollY = scrollY + deltaY;
 
    // Clamp values if at the limits and record
    final int left = -maxOverScrollX;
    final int right = maxOverScrollX + scrollRangeX;
    final int top = -maxOverScrollY;
    final int bottom = maxOverScrollY + scrollRangeY;
 
    boolean clampedX = false;
    if (newScrollX > right) {
        newScrollX = right;
        clampedX = true;
    } else if (newScrollX < left) {
        newScrollX = left;
        clampedX = true;
    }
 
    boolean clampedY = false;
    if (newScrollY > bottom) {
        newScrollY = bottom;
        clampedY = true;
    } else if (newScrollY < top) {
        newScrollY = top;
        clampedY = true;
    }
    …………
    return clampedX || clampedY;
}
我们把上拉、下拉的代码提取出来是这样的:
protected boolean overScrollBy(int deltaX, int deltaY,
        int scrollX, int scrollY,
        int scrollRangeX, int scrollRangeY,
        int maxOverScrollX, int maxOverScrollY,
        boolean isTouchEvent) {
    
    …………
int newScrollY = scrollY + deltaY;
 
    final int top = -maxOverScrollY;
    final int bottom = maxOverScrollY + scrollRangeY;
 
    boolean clampedY = false;
    if (newScrollY > bottom) {
        newScrollY = bottom;
        clampedY = true;
    } else if (newScrollY < top) {
        newScrollY = top;
        clampedY = true;
    }
    …………
    return clampedX || clampedY;
}
所以上面就是在overScrollBy中判断是否到顶、到底的方法,在OverScrollList中仿照一下,应该是这样写的:
protected boolean overScrollBy(int deltaX, int deltaY,
        int scrollX, int scrollY,
        int scrollRangeX, int scrollRangeY,
        int maxOverScrollX, int maxOverScrollY,
        boolean isTouchEvent) {
        
    int newScrollY = scrollY + deltaY;
    
    final int top = -maxOverScrollY;
    final int bottom = maxOverScrollY + scrollRangeY;
 
    if (newScrollY > bottom) {
        System.out.println("滑动到底端");
    } else if (newScrollY < top) {
         System.out.println("滑动到顶端");
    }
    return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
这才是正宗的判断是否到底、到顶的方法,至于为什么这么写,我也懒得研究了,无外乎就是弄懂scrollRangeY的含义而已。大家可以看看源码。其实,我觉得overScrollBy()的最大用途就是判断是否到底、到顶,至于什么下拉回弹,bug一堆!!!根本无法实际用到项目中!这里也只是给大家讲下这种实现方法而已,下篇我们会通过拦截OnTouchEvent()自己来实现下拉回弹。

三、带header的下拉回弹
这部分带着大家实现开篇的实现的效果。

1、listView添加透明header
(1)、概述

根据上面的效果图,我们直接来看看MainActivity的新布局代码:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent"
              android:layout_height="fill_parent">
    <ImageView
            android:id="@+id/background_img"
            android:layout_width="match_parent"
            android:layout_height="400dp"
            android:layout_marginTop="-100dp"
            android:scaleType="fitXY"
            android:src="@drawable/pic3" />
 
    <com.harvic.OverScrollDemo.OverScrollList
            android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="@null"
            android:dividerPadding="0dp"
            android:dividerHeight="0dp"/>
</FrameLayout>
与前几篇一样,同样为ImageView添加layout_marginTop="-100dp",让其先向上移一部分,以防下拉时出现空白。
不一样的是,这里的OverScrollList控件,是全屏显示的,我们要怎么样把底部的小狗显示出来呢?
可能大家最先想到把底部的小狗图片给空出来的方法,就是给listview添加margin或者padding,那添加margin或者padding到底行不行呢?我们为OverScrollList添加一个android:paddingTop="100dp"看一下效果:

从效果图中可以看到,在上滑时,ListView没办法滑动到屏幕顶部。所以,我们唯一的解决方案就是为OverScrollList添加一个透明header来占据空间。

(2)、header布局

下面就为listview添加一个透明的header,布局文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="100dp">
</LinearLayout>
在这里什么都没有定义,只定义了一个高度。这里也可以定义背景是透明的,但如果listview有背景的话,依然会被盖住,所以要确保listview是没有背景的。不过我们不添加背景的话,默认就是透明的了。
(3)、MainActivity中添加header
给ListView添加Header很简单,直接调用addHeaderView(View v)就可以了。代码如下 :

public class MyActivity extends Activity {
    private String[] mStrings = {"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
            "Allgauer Emmentaler", "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
            "Allgauer Emmentaler"};
    private LinkedList<String> mListItems;
    private OverScrollListView mListView;
    private ArrayAdapter<String> mAdapter;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        mListView = (OverScrollListView) findViewById(R.id.listview);
 
        ImageView headerView = (ImageView)findViewById(R.id.background_img);
        mListView.setmHeaderView(headerView);
 
        mListItems = new LinkedList<String>();
        mListItems.addAll(Arrays.asList(mStrings));
        mAdapter = new ArrayAdapter<String>(this,R.layout.item_layout, mListItems);
 
        LayoutInflater inflater = getLayoutInflater();
        View view = inflater.inflate(R.layout.headerview,mListView,false);
        mListView.addHeaderView(view);
 
        mListView.setAdapter(mAdapter);
    }
}
其实最关键的就是这句:
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.headerview,mListView,false);
mListView.addHeaderView(view);
没什么难度,就是根据layout获取到view,然后将其设置给list
2、实现底部图片下拉回弹
(1)、OverScrollList中的实现

们现在能够通过重新OverScrollBy()函数让系统自已给我们实现ListView的下拉回弹,但底部的小狗图片可还是要我们自己实现下拉和回弹的。
非常庆幸的是,在OverScrollBy()的一堆参数中:
overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) 
有两个参数对我们来讲特别有用:
scrollY:在加上deltaY以前的滚动距离;(向上移动时为正值,向下移动时为负值)
deltaY:此次的手指移动距离(同样,向上移动时为正值,向下移动时为负值)
所以我们将scrollY与deltaY相加就可以得到当前的滚动距离了,由于在回弹时OverScrollBy()也会被调用,所以整个过程在下拉时newScrollY就会一直变到最大,而在回弹时,newScrollY会慢慢减为0;
所以我们根据这个特性,直接根据当前的滚动距离计算出当前小狗图片的位置即可
完整的代码如下:

/**
 * 阻尼系数,越小阻力就越大.
 */
public static final float SCROLL_RATIO = 0.25f;
private Rect mHeadInitRect = new Rect();
//设置topView
private View mTopView;
public void setTopView(View view) {
    mTopView = view;
}
//初始化TopView的原始位置
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        mHeadInitRect.set(mTopView.getLeft(), mTopView.getTop(), mTopView.getRight(), mTopView.getBottom());
    }
    return super.onInterceptTouchEvent(ev);
}
//随下拉滚动
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
 
    int headerMoveHeight = (int)Math.abs((scrollY + deltaY) * SCROLL_RATIO);
    int mHeaderCurTop = (int) (mHeadInitRect.top + headerMoveHeight);
    mTopView.layout(mHeadInitRect.left, mHeaderCurTop, mHeadInitRect.right, (int) (mHeadInitRect.bottom + headerMoveHeight));
    return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mContentMaxMoveHeight, isTouchEvent);
}
这里总共分为三部分:
第一:将topView设置进来:
//设置topView
private View mTopView;
public void setTopView(View view) {
    mTopView = view;
}
第二:在手指下按点击时,初始化mTopView的位置。
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        mHeadInitRect.set(mTopView.getLeft(), mTopView.getTop(), mTopView.getRight(), mTopView.getBottom());
    }
    return super.onInterceptTouchEvent(ev);
}
在第二篇中,我们有讲过为什么mTopView的位置初始化操作要放在onInterceptTouchEvent中,这里再絮叨一遍:因为,要获取mTopView的位置获取要在onLayout()以后才可以得到,也就是要在整个控件绘制完以后才能获取它的显示位置。所以在OverScrollList的构造函数中,是获取不到它的位置的。大家还记得《FlowLayout详解(一)——onMeasure()与onLayout()》   中说的那句吗:首先getMeasureWidth()方法在measure()过程结束后就可以获取到了,而getWidth()方法要在layout()过程结束后才能获取到.这里同样的道理。
第三:随下拉滚动
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
 
    int headerMoveHeight = (int)Math.abs((scrollY + deltaY) * SCROLL_RATIO);
    int mHeaderCurTop = (int) (mHeadInitRect.top + headerMoveHeight);
    mTopView.layout(mHeadInitRect.left, mHeaderCurTop, mHeadInitRect.right, (int) (mHeadInitRect.bottom + headerMoveHeight));
    return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, mContentMaxMoveHeight, isTouchEvent);
}
要注意:
在向下移动时,scrollY和deltaY都是负值,所以要计算移动距离需要在外面加一层Math.abs()来取绝对值。
至于为什么在计算headerMoveHeight时要将移动距离乘以SCROLL_RATIO,在第二篇中也提到过,就是让小狗图片移动的慢一些,显得难拉一点,这比较符合正常思维
(2)、MainActivity中调用setmHeaderView
这里就非常简单了,就是调用OverScrollList的setTopView()将底部的小狗图片设置进去。
代码如下:(这段代码没什么难度,就不再细讲了)

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
 
    mListView = (OverScrollList) findViewById(R.id.listview);
 
    //设置topView
    ImageView topView = (ImageView)findViewById(R.id.background_img);
    mListView.setTopView(topView);
 
    //设置headerView
    LayoutInflater inflater = getLayoutInflater();
    View view = inflater.inflate(R.layout.headerview,mListView,false);
    mListView.addHeaderView(view);
 
    //初始化Adapter
    mListItems = new LinkedList<String>();
    mListItems.addAll(Arrays.asList(mStrings));
    mAdapter = new ArrayAdapter<String>(this,R.layout.item_layout, mListItems);
 
    mListView.setAdapter(mAdapter);
 
}
好了,到这里基本上就结束了,下面还有两个问题需要改进,然后就完整给出大家源码。
3、问题改进
(1)、OverScrollList的透明headerView在点击时会变白

答:我们就让它不可点击就可以了。在添加headview时,调用public void addHeaderView(View v, Object data, boolean isSelectable),将isSelectable设置为false即可,代码如下:

//设置headerview不可点击
mListView.addHeaderView(view, null, false);
非常注意,在headview对应的xml中设置clickable="false"是没有作用的;也就是下面的代码是没有作用的:(headview.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="100dp"
              android:clickable="false">
    <!--如果要让headview不可点击,在这里设置clickable="false"是没用的,只有通过ListView.addHeaderView(view,null,false);来设置-->
 
</LinearLayout>
(2)、到底部时,仍然可以向上拉,怎么实现只顶部下拉
答:还记得我们上面有讲过,如何利用overScrollView监听到底到顶吗?这里就派上用场啦。我们可以监听是否已经到底,如果到底就将maxOverScrollY设为0,如果是顶部就设为mContentMaxMoveHeight;
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
    //监听是否到底,如果到底就将maxOverScrollY设为0
    int newScrollY = scrollY + deltaY;
    final int bottom = maxOverScrollY + scrollRangeY;
    final int top = -maxOverScrollY;
    if (newScrollY > bottom) {
        maxOverScrollY = 0;
    } else if (newScrollY < top) {
        maxOverScrollY = mContentMaxMoveHeight;
    }
    //在向下移动时,scrollY是负值,所以scrollY + deltaY应该是当前应当所在位置。而由于scrollY + deltaY是负值,所以外层要包一个Math.abs()来取绝对值
    int headerMoveHeight = (int)Math.abs((scrollY + deltaY) * SCROLL_RATIO);
    int mHeaderCurTop = (int) (mHeadInitRect.top + headerMoveHeight);
    mTopView.layout(mHeadInitRect.left, mHeaderCurTop, mHeadInitRect.right, (int) (mHeadInitRect.bottom + headerMoveHeight));
    return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
}
好了,所有的都讲完了

四、OverScrollBy()存在问题
在实际应用中,发现有两个内部实现问题:
1、手指滑出屏幕后,不会回弹。
2、如果在下拉到底以后,弹出一个Fragment把当前页面盖在后面,即使这个Fragment是透明的,也会导致OverScrollBy()卡住不会回弹,即使自己回弹,也不会在回弹时调用overScrollBy(),导致其它底部小狗图片回弹出错。

好啦,这里就不再啰嗦了,下篇给大家讲述怎么使用OnTouchEvent()来实现下拉回弹的效果,这才正宗。
 

这篇关于PullScrollView详解(四)——完全使用listview实现下拉回弹(方法一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/754971

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi