前言:经常说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)》
ScrollView->FrameLayout->ViewGroup->View
ListView->AbsListView->AdapterView->ViewGroup->View
从上面的派生中都可以看出,全部都是派生自View,而且全部都没有对getScrollY()方法重写。那就奇怪了,大家都没有对它进行重写。那肯定是设置的问题了。
在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中都调这两个函数做了什么。
由于ScrollView直接派生自FrameLayout,所以我们直接看ScrollView.java中做了什么就可以了。
首先,看setScrollY(int value)的用处,木有地方调。
好吧,那我们再来看看ScrollTo(int x,int y)用到的地方。
在OnTouchEvent()中,最关键的一句应该在这里:
@Override protected 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()中又做了什么;
/** * 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;
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) { // Intentionally empty. }那我们再来看看AbsListView.java中,onOverScrolled都做了些什么吧。
@Override protected 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进行了赋值。其它时间都没有进行赋值!!!!
@Override protected 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()来实现上、下拉滑动的!!!!
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);
}
}
<?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>
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 谢谢