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

本文主要是介绍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()中,最关键的一句应该在这里:

@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()中又做了什么;
在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都做了些什么吧。
@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进行了赋值。其它时间都没有进行赋值!!!!


延伸二:ScrollView中重写overScrollBy()实现上、下拉滑动
就在上面对比源码的时候,偶然发现ScrollView竟然也重写onOverScrolled(),源码如下:(ScrollView.java中)
@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()来实现上、下拉滑动的!!!!
下面就举个栗子来看下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);
        }
    }
}
好啦 ,到这里代码就结束了。这个系列也就结束了,写了太多内容,一个貌似不复杂的动画没想到会牵涉这么多内容。能努力看完的同学,也都是不容易啊。
 

这篇关于PullScrollView详解(六)——延伸拓展(listview中getScrollY()一直等于0、ScrollView中的overScrollBy)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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

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

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

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

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

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

LabVIEW FIFO详解

在LabVIEW的FPGA开发中,FIFO(先入先出队列)是常用的数据传输机制。通过配置FIFO的属性,工程师可以在FPGA和主机之间,或不同FPGA VIs之间进行高效的数据传输。根据具体需求,FIFO有多种类型与实现方式,包括目标范围内FIFO(Target-Scoped)、DMA FIFO以及点对点流(Peer-to-Peer)。 FIFO类型 **目标范围FIFO(Target-Sc

019、JOptionPane类的常用静态方法详解

目录 JOptionPane类的常用静态方法详解 1. showInputDialog()方法 1.1基本用法 1.2带有默认值的输入框 1.3带有选项的输入对话框 1.4自定义图标的输入对话框 2. showConfirmDialog()方法 2.1基本用法 2.2自定义按钮和图标 2.3带有自定义组件的确认对话框 3. showMessageDialog()方法 3.1

脏页的标记方式详解

脏页的标记方式 一、引言 在数据库系统中,脏页是指那些被修改过但还未写入磁盘的数据页。为了有效地管理这些脏页并确保数据的一致性,数据库需要对脏页进行标记。了解脏页的标记方式对于理解数据库的内部工作机制和优化性能至关重要。 二、脏页产生的过程 当数据库中的数据被修改时,这些修改首先会在内存中的缓冲池(Buffer Pool)中进行。例如,执行一条 UPDATE 语句修改了某一行数据,对应的缓

OmniGlue论文详解(特征匹配)

OmniGlue论文详解(特征匹配) 摘要1. 引言2. 相关工作2.1. 广义局部特征匹配2.2. 稀疏可学习匹配2.3. 半稠密可学习匹配2.4. 与其他图像表示匹配 3. OmniGlue3.1. 模型概述3.2. OmniGlue 细节3.2.1. 特征提取3.2.2. 利用DINOv2构建图形。3.2.3. 信息传播与新的指导3.2.4. 匹配层和损失函数3.2.5. 与Super