Android ListView 弹性滚动简单实现

来源:互联网 发布:淘宝卖家网页制作 编辑:程序博客网 时间:2024/05/21 17:42

通常情况下,Android默认的ListView 在滚动到顶端或底端的时候,并没有很好的提示。在IOS系统的交互中,列表是有弹性的,当列表滑动到顶部或者底部时会继续往上或者往下滑动一段距离。但是在Android系统中,Google并没有赋予listview这种良好的交互效果,仅在Android 5.X版本的系统中,给这种行为添加了一个半月型的波纹阴影。

搜了一下网上的解决方案,基本上都是通过重写ListView来实现弹性效果的。比如增加HeaderView 或者嵌套scrollView,方法很多,这里不再赘述。不过这篇博文主要给大家介绍一个非常简单的方法来实现这种效果。

查看ListView的源代码时候可以发现,其中一个方法,可以控制ListView滑动到边缘的处理方法,源码如下:

/**     * 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.     *     * Views can use this method to handle any touch or fling-based scrolling.     *     * @param deltaX Change in X in pixels     * @param deltaY Change in Y in pixels     * @param scrollX Current X scroll value in pixels before applying deltaX     * @param scrollY Current Y scroll value in pixels before applying deltaY     * @param scrollRangeX Maximum content scroll range along the X axis     * @param scrollRangeY Maximum content scroll range along the Y axis     * @param maxOverScrollX Number of pixels to overscroll by in either direction     *          along the X axis.     * @param maxOverScrollY Number of pixels to overscroll by in either direction     *          along the Y axis.     * @param isTouchEvent true if this scroll operation is the result of a touch event.     * @return true if scrolling was clamped to an over-scroll boundary along either     *          axis, false otherwise.     */    @SuppressWarnings({"UnusedParameters"})    protected boolean overScrollBy(int deltaX, int deltaY,            int scrollX, int scrollY,            int scrollRangeX, int scrollRangeY,            int maxOverScrollX, int maxOverScrollY,            boolean isTouchEvent) {        final int overScrollMode = mOverScrollMode;        final boolean canScrollHorizontal =                computeHorizontalScrollRange() > computeHorizontalScrollExtent();        final boolean canScrollVertical =                computeVerticalScrollRange() > computeVerticalScrollExtent();        final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS ||                (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal);        final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS ||                (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical);        int newScrollX = scrollX + deltaX;        if (!overScrollHorizontal) {            maxOverScrollX = 0;        }        int newScrollY = scrollY + deltaY;        if (!overScrollVertical) {            maxOverScrollY = 0;        }        // 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;    }

从注释当中可以看到这样一个参数

maxOverScrollY
Number of pixels to overscroll by in either >direction along the Y axis.

这个参数标识了ListView 沿Y轴方向超出范围滚动的像素数,我们可以修改这个值,就可以让ListView具有弹性。只要重写ListView中的这个方法,设置maxOverScrollY 为我们自己定义的偏移值maxOverOffset.代码如下:

public class FlexibleListView extends ListView {    private static int maxOverOffset = 50;    private Context mContext;    public FlexibleListView(Context context, AttributeSet attrs,                            int defStyleAttr) {        super(context, attrs, defStyleAttr);        this.mContext = context;        initView();    }    public FlexibleListView(Context context, AttributeSet attrs) {        super(context, attrs);        this.mContext = context;        initView();    }    public FlexibleListView(Context context) {        super(context);        this.mContext = context;        initView();    }    private void initView() {        DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();        float density = metrics.density;        //Log.d("TAG", "屏幕密度比例因子为" + density);        maxOverOffset = (int) (density * maxOverOffset);    }    @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, maxOverOffset,                isTouchEvent);    }}

注意,为了保持不同分辨率屏幕下弹性距离保持基本保持一致,偏移值 maxOverOffset 根据屏幕密度比例进行了重新计算。

效果如下图所示:
这里写图片描述

完整demo读者自己写下,比较简单,这里不再给出,这个例子提醒我们,平常在开发过程中注意阅读源码,往往能得到意想不到的结果。

1 0
原创粉丝点击