码迷,mamicode.com
首页 > 移动开发 > 详细

Android---可以实现下拉刷新的ListView

时间:2016-07-13 16:58:53      阅读:236      评论:0      收藏:0      [点我收藏+]

标签:

1.效果

技术分享
这个效果在很多App里都可以用到,基本上就已经泛滥了.这里就记录一下如何实现这一种效果.(截图没注意大小,丢帧也严重,所以看上去有点卡顿)

2.实现步骤

2.1布局文件
技术分享
首先要明确的是,这一块也是一个布局文件,我们首先写出这个layout,代码比较简单,就不做说明了:

pull_to_refesh.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:orientation="horizontal">

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp">

        <ImageView
            android:id="@+id/iv_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@drawable/common_listview_headview_red_arrow"/>

        <ProgressBar
            android:id="@+id/pb_loading"
            android:visibility="invisible"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"/>

    </FrameLayout>

    <LinearLayout
        android:paddingRight="50dp"
        android:layout_marginTop="13dp"
        android:gravity="center"
        android:layout_width="0dp"
        android:orientation="vertical"
        android:layout_height="wrap_content"
        android:layout_weight="1">

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="下拉刷新"
            android:textColor="#f00"
            android:textSize="18sp"/>

        <TextView
            android:id="@+id/tv_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="2016-07-12 14:00:20"
            android:textColor="#a000"
            android:textSize="16sp"/>


    </LinearLayout>

</LinearLayout>

2.2创建一个类继承自ListView

public class PullToRefreshListView extends ListView {}

在这个类里面,我们去实现下拉刷新.

2.3 initView()

    private void initView() {
            mHeaderView = View.inflate(getContext(), R.layout.pull_to_refesh, null);

        //作为ListView 的headerView
        this.addHeaderView(mHeaderView);

        tv_title = (TextView) mHeaderView.findViewById(R.id.tv_title);
        tv_time = (TextView) mHeaderView.findViewById(R.id.tv_time);
        iv_arrow = (ImageView) mHeaderView.findViewById(R.id.iv_arrow);
        pb_loading = (ProgressBar) mHeaderView.findViewById(R.id.pb_loading);


        //隐藏掉下拉刷新的头布局
        mHeaderView.measure(0, 0);
        mHeaderViewHeight = mHeaderView.getMeasuredHeight();
        mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);

        //初始化Animation
        initAnimation();

        //初始化现在时间
        setCurrentTime();
    }

2.3.1
在这个方法里,我们将pull_to_refesh.xml转换成的view对象mHeaderView,作为headerView设置给当前自定义的ListView

this.addHeaderView(mHeaderView);

2.3.2
再将mHeaderView隐藏起来:

        mHeaderView.measure(0, 0);
        mHeaderViewHeight = mHeaderView.getMeasuredHeight();
        mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);

2.3.3
初始化动画的方法,在效果图中,我们可以看到,当下拉刷新时候,向下的箭头会有一个180度的旋转动画:

private void initAnimation() {
        mRotateAnimationUp = new RotateAnimation(0, 180,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        mRotateAnimationUp.setDuration(2000);
        mRotateAnimationUp.setFillAfter(true);

        mRotateAnimationDown = new RotateAnimation(180,0,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        mRotateAnimationDown.setDuration(2000);
        mRotateAnimationDown.setFillAfter(true);
    }

2.3.4
刷新后设置时间的方法:

public void setCurrentTime(){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = simpleDateFormat.format(new Date());
        tv_time.setText(time);
    }

2.4重写onTouchEvent()方法
先贴出方法,在分析

@Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mStartY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                mEndY = (int) ev.getY();
                //当用户按住头条新闻的ViewPager下来时,ACTION_DOWN事件会被ViewPager消耗,导致mStartY没有被赋值
                //所以在此处需要重新的拿Y值
                if (mStartY == -1) {
                    mStartY = (int) ev.getY();
                }

                //如果现在的状态是正在刷新,那么直接跳出循环
                if (mCurrentState==ConstantValues.STATE_REFRESHING){
                    break;
                }
                //在Y方向上的偏移量
                int dy = mEndY - mStartY;

                //拿到当前显示的第一个item的位置
                int firstVisiblePosition = getFirstVisiblePosition();

                Log.d("firstVisiblePosition------>",firstVisiblePosition+"");

              //下拉&&当前显示的是第一个item (mHeaderView)
                if (dy > 0 && firstVisiblePosition == 0) {

                    int padding = dy - mHeaderViewHeight;

                    Log.d("------>", "dy--->" + dy + "--->mHeaderViewHeight" + mHeaderViewHeight + "--->padding" + padding);

                    mHeaderView.setPadding(0, padding, 0, 0);

                    if (padding > 0 && mCurrentState != ConstantValues.STATE_RELEASE_TO_REFRESH) {
                        //改为松开刷新
                        mCurrentState = ConstantValues.STATE_RELEASE_TO_REFRESH;
                        refreshState();

                    } else if (padding < 0 && mCurrentState != ConstantValues.STATE_PULL_TO_REFRESH) {
                        //改为下拉刷新
                        mCurrentState = ConstantValues.STATE_PULL_TO_REFRESH;
                        refreshState();
                    }

                    return true;

                }

                break;
            case MotionEvent.ACTION_UP:
                //为下一次刷新做准备,重新赋值为-1
                mStartY=-1;

                if (mCurrentState==ConstantValues.STATE_RELEASE_TO_REFRESH){
                    mCurrentState=ConstantValues.STATE_REFRESHING;
                    refreshState();
                    //完整展示头布局
                    mHeaderView.setPadding(0,0,0,0);


                    /**
                    *4.(合适的时机)进行回调
                    *@author zfy
                    *@created at 2016/7/12 14:23
                    */
                    if (mListener!=null){
                        mListener.onRefresh();
                    }

                }else if (mCurrentState==ConstantValues.STATE_PULL_TO_REFRESH){
                    //隐藏头布局
                    mHeaderView.setPadding(0,-mHeaderViewHeight,0,0);
                }


                break;
        }


        return super.onTouchEvent(ev);
    }
  • 首先会有mCurrentState这个量,表示的是下拉栏当前的状态

     1.STATE_PULL_TO_REFRESH=1;表示目前处于需要被下拉的状态
     2.STATE_RELEASE_TO_REFRESH=2;表示目前处于需要松手的状态
     3.STATE_REFRESHING=3;表示目前处于正在刷新的状态
    
  • ACTION_DOWN时候拿到当前的Y值mStartY = (int) ev.getY();默认等于-1

  • ACTION_MOVE时候:我们根据当前下拉的位置padding,重新设置mHeaderView的padding值.并修改当前的下拉状态

  • ACTION_UP的时候:对mStartY重新赋值,并且进行回调.

  • 其中根据状态值重新刷新界面的方法refreshState如下:
 private void refreshState() {
        switch (mCurrentState) {
            case ConstantValues.STATE_PULL_TO_REFRESH:
                tv_title.setText("下拉刷新");
                iv_arrow.startAnimation(mRotateAnimationDown);
                pb_loading.setVisibility(View.INVISIBLE);
                iv_arrow.setVisibility(View.VISIBLE);
                break;
            case ConstantValues.STATE_RELEASE_TO_REFRESH:
                tv_title.setText("松开刷新");
                iv_arrow.startAnimation(mRotateAnimationUp);
                pb_loading.setVisibility(View.INVISIBLE);
                iv_arrow.setVisibility(View.VISIBLE);
                break;
            case ConstantValues.STATE_REFRESHING:
                tv_title.setText("正在刷新...");

                //清除箭头动画,否则不能隐藏
                iv_arrow.clearAnimation();

                pb_loading.setVisibility(View.VISIBLE);
                iv_arrow.setVisibility(View.INVISIBLE);
                break;
        }

    }

2.5回调

  1. 定义下拉刷新的接口
  2. 暴露接口设置监听
  3. 定义成员变量接收监听对象
  4. 在合适的时机进行回调
  5. 在前端逻辑界面设置回调
   /**
     * 3.定义成员变量接收监听对象
     *
     * @author zfy
     * @created at 2016/7/12 14:09
     */
    private OnRefreshListener mListener;

    /**
     * 2.暴露接口设置监听
     *
     * @author zfy
     * @created at 2016/7/12 14:08
     */
    public void setOnRefreshListener(OnRefreshListener listener) {
        mListener = listener;
    }

    /**
     * 1.下拉刷新的回调接口
     *
     * @author zfy
     * @created at 2016/7/12 14:06
     */
    public interface OnRefreshListener {
        public void onRefresh();
    }

步骤4在onTouchEvent方法中实现
步骤5在前段从服务器再次请求数据时候调用

/**
         *5.前端界面设置回调
         *@author zfy
         *@created at 2016/7/12 14:14
         */
        lv_list.setOnRefreshListener(new PullToRefreshListView.OnRefreshListener() {
            @Override
            public void onRefresh() {

                //从服务器中重新拿数据的方法
                getDataFromServer();

            }
        });

2.6刷新数据之后,隐藏下拉刷新头View的方法

 /**
    *刷新完成后收起头View的方法
    *@author zfy
    *@return
    *@param success 是否成功刷新
    *@created at 2016/7/12 14:56
    */
    public void onRefreshComplete(boolean success){
        mHeaderView.setPadding(0,-mHeaderViewHeight,0,0);
        tv_title.setText("下拉刷新");
        mCurrentState=ConstantValues.STATE_PULL_TO_REFRESH;
        pb_loading.setVisibility(INVISIBLE);
        iv_arrow.setVisibility(VISIBLE);
        if (success) {

            setCurrentTime();
        }
    }

这个方法在回调步骤5,重新从服务器拿数据方法getDataFromServer()内部调用

三.补充

  • 上述步骤完成之后,下拉刷新的方法基本就已经实现了.
  • 下拉刷新的实现过程也差不多就是一个简单的自定义View的过程
  • 这个功能也大可不必自己手敲,很多开源类库都已经实现了这个功能.

Android---可以实现下拉刷新的ListView

标签:

原文地址:http://blog.csdn.net/sinat_33661267/article/details/51890227

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!