前言:今天看到一篇文章,非常喜欢其中的一句话,送给大家——如果万事俱备,那还要你干嘛。
相关文章:
1、《PullScrollView详解(一)——自定义控件属性》
2、《PullScrollView详解(二)——Animation、Layout与下拉回弹》
3、《PullScrollView详解(三)——PullScrollView实现》
4、《PullScrollView详解(四)——完全使用listview实现下拉回弹(方法一)》
5、《PullScrollView详解(五)——完全使用listview实现下拉回弹(方法二)》
6、《PullScrollView详解(六)——延伸拓展(listview中getScrollY()一直等于0、ScrollView中的overScrollBy)》
在前面三篇中,我为大家展示了使用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;
-
- 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);
-
- 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;
-
-
- 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,然后将其设置给list2、实现底部图片下拉回弹
(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();
-
- private View mTopView;
- public void setTopView(View view) {
- mTopView = view;
- }
-
- @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设置进来:-
- 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);
-
-
- ImageView topView = (ImageView)findViewById(R.id.background_img);
- mListView.setTopView(topView);
-
-
- LayoutInflater inflater = getLayoutInflater();
- View view = inflater.inflate(R.layout.headerview,mListView,false);
- mListView.addHeaderView(view);
-
-
- 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即可,代码如下:
-
- 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) {
-
- int newScrollY = scrollY + deltaY;
- final int bottom = maxOverScrollY + scrollRangeY;
- final int top = -maxOverScrollY;
- if (newScrollY > bottom) {
- maxOverScrollY = 0;
- } else if (newScrollY < top) {
- maxOverScrollY = mContentMaxMoveHeight;
- }
-
- 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()来实现下拉回弹的效果,这才正宗。源码内容:
1、《二、简单示例》:对应框架部分代码
2、《最终源码》:最终代码
如果本文有帮到你,记得加关注哦
源码下载地址:http://download.csdn.net/detail/harvic880925/9052605
请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/48021931 谢谢
0 0