PullScrollView详解(六)——延伸拓展(listview中getScrollY()一直等于0、ScrollView中的overScrollBy)

来源:互联网 发布:浏览器java插件下载 编辑:程序博客网 时间:2024/05/16 01:53

前言:经常说follow your heart。但等到真到这么一天的时候,却很艰难

相关文章:

1、《PullScrollView详解(一)——自定义控件属性》
2、《PullScrollView详解(二)——Animation、Layout与下拉回弹》
3、《PullScrollView详解(三)——PullScrollView实现》
4、《PullScrollView详解(四)——完全使用listview实现下拉回弹(方法一)》
5、《PullScrollView详解(五)——完全使用listview实现下拉回弹(方法二)》
6、《PullScrollView详解(六)——延伸拓展(listview中getScrollY()一直等于0、ScrollView中的overScrollBy)》

延伸一:为什么PullScrollView中getScrollY()有值而ListView中的getScrollY()却一直为零

通过查源码,你会发现getScrollY()是View的一个方法。那ScrollView为什么getScrollY()有值呢?
让我们仔细分析一下源码:

(1)、先看派生

ScrollView->FrameLayout->ViewGroup->View
ListView->AbsListView->AdapterView->ViewGroup->View
从上面的派生中都可以看出,全部都是派生自View,而且全部都没有对getScrollY()方法重写。那就奇怪了,大家都没有对它进行重写。那肯定是设置的问题了。

(2)、设置scrollY的区别

在View.java中,有两个函数能对ScrollY进行设置:

public void setScrollY(int value) {    scrollTo(mScrollX, value);}public void scrollTo(int x, int y) {    if (mScrollX != x || mScrollY != y) {        int oldX = mScrollX;        int oldY = mScrollY;        mScrollX = x;        mScrollY = y;        invalidateParentCaches();        onScrollChanged(mScrollX, mScrollY, oldX, oldY);        if (!awakenScrollBars()) {            invalidate(true);        }    }}
那分别来看看ScrollView和ListView中都调这两个函数做了什么。

(3)、ScrollVIew中的ScrollY的设置

由于ScrollView直接派生自FrameLayout,所以我们直接看ScrollView.java中做了什么就可以了。
首先,看setScrollY(int value)的用处,木有地方调。
好吧,那我们再来看看ScrollTo(int x,int y)用到的地方。
在OnTouchEvent()中,最关键的一句应该在这里:

@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {    super.onLayout(changed, l, t, r, b);    mIsLayoutDirty = false;    // Give a child focus if it needs it    if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {        scrollToChild(mChildToScrollTo);    }    mChildToScrollTo = null;    // Calling this with the present values causes it to re-clam them    scrollTo(mScrollX, mScrollY);}

在每一次重绘时,都会调用scrollTo()重新设置mScrollY的值,所以,当我们在获取时,是可以获取到的。
那再来看看Listview中,是如何做的:
木有setScrollY(int value)和ScrollTo(int x,int y)的调用。貌似理解了为什么getScrollY()没值的原因了。
但为什么在上篇中重写OverScrollBy()时scrollY是有值的呢?那我们再找找overScrollBy()的整个调用流程:
首先在OnTouchEvent()的ACTION_MOVE中:(在AbsListView.java中)

case MotionEvent.ACTION_MOVE: {…………    final int y = (int) ev.getY(pointerIndex);    switch (mTouchMode) {    case TOUCH_MODE_DOWN:    case TOUCH_MODE_TAP:    case TOUCH_MODE_DONE_WAITING:        // Check if we have moved far enough that it looks more like a        // scroll than a tap        startScrollIfNeeded(y);        break;    case TOUCH_MODE_SCROLL:    case TOUCH_MODE_OVERSCROLL:        scrollIfNeeded(y);        break;    }    break;}
在MotionEvent.ACTION_MOVE中会走到scrollIfNeeded(y);中(在AbsListView.java中)
private void scrollIfNeeded(int y) {    final int rawDeltaY = y - mMotionY;    final int deltaY = rawDeltaY - mMotionCorrection;    int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;    if (mTouchMode == TOUCH_MODE_SCROLL) {        if (y != mLastY) {            ………………            if (motionView != null) {                // Check if the top of the motion view is where it is                // supposed to be                final int motionViewRealTop = motionView.getTop();                if (atEdge) {                    // Apply overscroll                    int overscroll = -incrementalDeltaY -                            (motionViewRealTop - motionViewPrevTop);                    overScrollBy(0, overscroll, 0, mScrollY, 0, 0,                            0, mOverscrollDistance, true);                    …………                }                mMotionY = y;                invalidate();            }            mLastY = y;        }    } else if (mTouchMode == TOUCH_MODE_OVERSCROLL) {        if (y != mLastY) {                        …………            if (overScrollDistance != 0) {                overScrollBy(0, overScrollDistance, 0, mScrollY, 0, 0,                        0, mOverscrollDistance, true);                …………                }            }…………        }    }}
从上面的源码中可以看到,正常滑动和OVERSCROLL时,都会判断当前是不是已经超出了边界,进而调用overScrollBy(),然后再看看OverScrollBy()中又做了什么;
在View.java中:
/*** Scroll the view with standard behavior for scrolling beyond the normal* content boundaries. Views that call this method should override* {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the* results of an over-scroll operation.*/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;   // 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;   }   onOverScrolled(newScrollX, newScrollY, clampedX, clampedY);   return clampedX || clampedY;}
可以看到overScrollBy()中并没有做什么,只是计算出当前最新的newScrollX和newScrollY,然后把结果传给onOverScrolled;
而View.java中的onOverScrolled()是一个空方法。从overScrollBy()方法上面的那一坨注释我们也不难看到,需要自己重写onOverScrolled()方法来实现overScorll的滚动。
protected void onOverScrolled(int scrollX, int scrollY,        boolean clampedX, boolean clampedY) {    // Intentionally empty.}
那我们再来看看AbsListView.java中,onOverScrolled都做了些什么吧。
@Overrideprotected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {    if (mScrollY != scrollY) {        onScrollChanged(mScrollX, scrollY, mScrollX, mScrollY);        mScrollY = scrollY;        invalidateParentIfNeeded();        awakenScrollBars();    }}
看到了吧,在这里对mScrollY重新进行了赋值。这也就是为什么在overScrollBy()的时候getScrollY()有值,而其它时候getScrollY()全是零的原因。因为只有在overScrollBy()的时候对mScrollY进行了赋值。其它时间都没有进行赋值!!!!

延伸二:ScrollView中重写overScrollBy()实现上、下拉滑动

就在上面对比源码的时候,偶然发现ScrollView竟然也重写onOverScrolled(),源码如下:(ScrollView.java中)
@Overrideprotected void onOverScrolled(int scrollX, int scrollY,        boolean clampedX, boolean clampedY) {    // Treat animating scrolls differently; see #computeScroll() for why.    if (!mScroller.isFinished()) {        mScrollX = scrollX;        mScrollY = scrollY;        invalidateParentIfNeeded();        if (clampedY) {            mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange());        }    } else {        super.scrollTo(scrollX, scrollY);    }    awakenScrollBars();}
上面我们说了overScrollBy()中其实什么都没做,只是计算出当前最新的移动距离,然后把结果传给onOverScrolled()而View自己的onOverScrolled()是个空函数,也就是说如果派生自View的控件要实现OverScrolled的功能,就需要自己重写onOverScrolled()函数,并在其中处理。所以凡是重写了onOverScrolled()的控件都是可以通过重写overScrollBy()来实现上、下拉滑动的!!!!
下面就举个栗子来看下ScrollView中实现overScrollBy()的方法吧。
先看看效果图:

效果很明显,也没什么好说的,跟《PullScrollView详解(四)——完全使用listview实现下拉回弹(方法一)》   效果一样,其实实现方法也完全一样。下面就看看代码吧

1、重写ScrollView

代码如下,就是重写overScrollBy()方法,设置里面的maxOverScrollY的值。

public class OverScrollView extends ScrollView {    //定义最大滚动高度    int mContentMaxMoveHeight = 250;    public OverScrollView(Context context) {        super(context);    }    public OverScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public OverScrollView(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    @Override    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);    }}

2、主布局(main.xml)

布局很容易理解,就是在OverScrollView里,放一个TableLayout来填充数据
<?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">    <com.harvic.OverScrollView.OverScrollView            android:id="@+id/scrollview"            android:layout_width="match_parent"            android:layout_height="match_parent">        <TableLayout                android:id="@+id/table_layout"                android:layout_width="match_parent"                android:layout_height="wrap_content"/>    </com.harvic.OverScrollView.OverScrollView></FrameLayout>

3、MainActivity.java数据填充

最后就是在MainActivity中对TableLayout进行数据填充,在第二篇和第三篇博客中都有填充的部分,代码都一样,就不再细讲了。
public class MainActivity extends Activity {    private TableLayout mMainLayout;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        mMainLayout = (TableLayout) findViewById(R.id.table_layout);        showTable();    }    public void showTable() {        TableRow.LayoutParams layoutParams = new TableRow.LayoutParams(                TableRow.LayoutParams.MATCH_PARENT,                TableRow.LayoutParams.WRAP_CONTENT);        layoutParams.gravity = Gravity.CENTER;        layoutParams.leftMargin = 30;        layoutParams.bottomMargin = 10;        layoutParams.topMargin = 10;        for (int i = 0; i < 30; i++) {            TableRow tableRow = new TableRow(this);            TextView textView = new TextView(this);            textView.setText("Test pull down scroll view " + i);            textView.setTextSize(20);            textView.setPadding(15, 15, 15, 15);            tableRow.addView(textView, layoutParams);            if (i % 2 != 0) {                tableRow.setBackgroundColor(Color.LTGRAY);            } else {                tableRow.setBackgroundColor(Color.WHITE);            }            final int n = i;            tableRow.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    Toast.makeText(getApplicationContext(), "Click item " + n, Toast.LENGTH_SHORT).show();                }            });            mMainLayout.addView(tableRow);        }    }}
好啦 ,到这里代码就结束了。这个系列也就结束了,写了太多内容,一个貌似不复杂的动画没想到会牵涉这么多内容。能努力看完的同学,也都是不容易啊。
源码在文章底部给出


如果本文有帮到你,记得加关注哦

源码下载地址:http://download.csdn.net/detail/harvic880925/9062283

请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/48092341  谢谢


5 0
原创粉丝点击