02月28, 2014

Android 扩展ListView的下拉刷新控件

工程需要使用下拉刷新,但是使用网上流传的各种版本均有或多或少的bug,或者效果不完美的地方。

效果图如下:

主要实现的特殊效果如下:

  1. 下拉时缩减手指滑动距离,实现越拉越难的效果
  2. 加载状态时,上推界面遮挡部分头部,头部自动收回
  3. 加载状态时,界面依然可以下拉,松手自动收回,只显示头部
  4. 加载完成后,有加载完成的状态,停留1秒之后自动收回
  5. ListView中数据长度没有充满屏幕时,可以下拉刷新
  6. ListView中没有数据时,可以下拉刷新
  7. 所有的下拉,回弹均有动画效果

具体的实现思路跟网上的是一样的,就是给ListView添加HeadView,默认隐藏,通过监听OnTouch、OnScroll事件实现滑动时的各种效果。

只说说在实现时遇到的几个问题是怎么解决的:

  1. 实现越拉越难的效果

在实现拉动越来越难的效果时,通过监听MotionEvent.ACTION_MOVE事件,取手指滑动距离的1/3,代码如下:


            if (currentHeaderState != REFRESH_BACED) {
                mHeaderLinearLayout.setPadding(
                        mHeaderLinearLayout.getPaddingLeft(), -mHeaderHeight
                                + (int) ((mMoveY - mDownY) / 3),
                        mHeaderLinearLayout.getPaddingRight(),
                        mHeaderLinearLayout.getPaddingBottom());
            } else if (currentHeaderState == REFRESH_BACED
                    && headVisible == true) {
                mHeaderLinearLayout.setPadding(
                        mHeaderLinearLayout.getPaddingLeft(),
                        (int) ((mMoveY - mDownY) / 3),
                        mHeaderLinearLayout.getPaddingRight(),
                        mHeaderLinearLayout.getPaddingBottom());
            } else if (currentHeaderState == REFRESH_BACED
                    && headVisible == false) {
                mHeaderLinearLayout.setPadding(
                        mHeaderLinearLayout.getPaddingLeft(), -mHeaderHeight
                                + (int) ((mMoveY - mDownY) / 3),
                        mHeaderLinearLayout.getPaddingRight(),
                        mHeaderLinearLayout.getPaddingBottom());

            }

下拉时一共有三种状态:A. 正常状态、B. 加载状态且头部隐藏、C.加载状态且头部显示。

其中A状态和B状态处理方式一样,直接从手指滑动开始计算,拉开滑动距离1/3的效果

C状态时,滑动时位置减去头部的高度,再开始滑动。

直接通过setPadding来实现滑开的效果,且滑动距离缩减1/3,如果手指不松开,来回滑动的话,会导致距离计算不正确,所以在设置回弹效果的时候,要做处理,不然会导致界面收回之后,List中的部分条目也被遮挡。

  1. 实现回弹动画

这个因为ListView也是在主界面的线程中,所以可以使用Handler.postDelayed()来实现,每次缩减剩余高度的1/4,5毫秒刷新一次即可。

这里主要实现了两个动画,一个是头部隐藏动画,用于未达到刷新状态,和遮挡部分加载中的头部时的动画

另外一个是头部收回动画,用于下拉高度超出头部高度时,头部的松手回弹动画,代码如下:

Runnable headHideAnimation = new Runnable() {
        public void run() {
            if (mHeaderLinearLayout.getBottom() > 0) {
                int paddingTop = (int) (-mHeaderHeight * 0.25f + mHeaderLinearLayout
                        .getPaddingTop() * 0.75f) - 1;
                if (paddingTop < -mHeaderHeight) {
                    paddingTop = -mHeaderHeight;
                }
                mHeaderLinearLayout.setPadding(
                        mHeaderLinearLayout.getPaddingLeft(), paddingTop,
                        mHeaderLinearLayout.getPaddingRight(),
                        mHeaderLinearLayout.getPaddingBottom());
                handler.postDelayed(headHideAnimation, 5);
            } else {
                handler.removeCallbacks(headHideAnimation);
                mHeaderLinearLayout.setPadding(
                        mHeaderLinearLayout.getPaddingLeft(), -mHeaderHeight,
                        mHeaderLinearLayout.getPaddingRight(),
                        mHeaderLinearLayout.getPaddingBottom());
                setSelection(1);
                headVisible = false;
            }
        }
    };

    Runnable headBackAnimation = new Runnable() {
        public void run() {
            if (mHeaderLinearLayout.getPaddingTop() > 1) {
                mHeaderLinearLayout.setPadding(
                        mHeaderLinearLayout.getPaddingLeft(),
                        (int) (mHeaderLinearLayout.getPaddingTop() * 0.75f),
                        mHeaderLinearLayout.getPaddingRight(),
                        mHeaderLinearLayout.getPaddingBottom());
                handler.postDelayed(headBackAnimation, 5);
            } else {
                headVisible = true;
                handler.removeCallbacks(headBackAnimation);
            }
        }
    };

  1. 实现ListView中数据没有充满屏幕时的下拉

当ListView中的数据没有充满屏幕的时候,滑动ListView没有内容的部分,监听不到onScrollStateChanged()事件,只能监听到onTouchEvent()、onScroll()这两个事件,如果不做特殊处理的话,会导致下拉之后状态不改变。

所以在onTouchEvent()中的Move事件中将界面的状态由静止改为滑动,即可解决问题。

本文链接:http://blogs.360.cn/post/android-扩展listview的下拉刷新控件.html

-- EOF --

Comments