代码改变世界

Android--简单的自定义ListView下拉刷新

2017-01-11 15:40  It一zhai男  阅读(4216)  评论(0编辑  收藏  举报

ListView下拉刷新一般要注意以下几点:

1. listview的头布局

2. 注意标志的应用,即刷新的几个状态,分别是下拉刷新,松开刷新和正在刷新

3. 注意几个动画效果,即箭头旋转,刷新图标旋转等

 

先上效果图:

                             

 

                                                                                                                               下面,我们来分别介绍。

先来说说这个demo里用到的几个方法。

(1)public boolean onTouchEvent(MotionEvent ev):这个方法是手势触摸事件。这里主要用到了MotionEvent.ACTION_DOWN(手势按下)、MotionEvent.ACTION_MOVE(手势滑动)和MotionEvent.ACTION_UP(手指抬起手势)。

 

下拉刷新,是先将listview的头部隐藏,然后用手势拖动屏幕刷新。那么,listview的头部如何隐藏呢?这里用的是header.setPadding(0,-headerViewHeight,0,0)来隐藏头部,这里不细说,等下介绍。如图1所示,要让listview的头部跟着手势一起向下滑动,则需要记录手指移动的距离。所以,当MotionEvent.ACTION_DOWN(手势按下)触发时,需要一个downY记录手势按下时y的偏移值,然后随着手势的滑动即MotionEvent.ACTION_MOVE(手势滑动)触发时,又需要一个moveY记录移动的偏移值,然后paddingTop=moveY-downY得到的就是手指滑动的距离。然后用paddingTop-headerViewHeight(相减的值设为x)得到头部的顶部到屏幕的顶部距离。如果想x>0则说明头部完全显示,如果x<0则头部没有完全显示。

 

这里要设置几个标志位

PULL_DOWN_REFRESH(下拉刷新):当头部未完全显示时为下拉刷新状态。

RELEASE_REFRESH(释放刷新):当头部完全显示时为释放刷新状态。

REFRESHING(正在刷新):当手势抬起,并头部完全显示时为正在刷新。

 

其他的都比较简单,在程序里都有注释,这里就不再赘述了。上代码:

RefreshListView.java

package com.example.yds.pulldowntest;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.AbsListView;
import android.widget.TextView;

import org.w3c.dom.Text;

/**
 * Created by yds on 2017/1/10.
 */

public class RefreshListView extends ListView implements AbsListView.OnScrollListener {
    //头布局视图
    private View header;
    //头布局高度
    private int headerViewHeight;
    //按下时y的偏移量
    private int downY;
    //移动时y的偏移量
    private int moveY;
    //距离顶部的距离
    private int paddingTop;
    //listview第一个可见的item项
    private int firstVisibleItemPosition;
    //下拉刷新
    private final int PULL_DOWN_REFRESH = 0;
    //释放刷新
    private  final int RELEASE_REFRESH = 1;
    //正在刷新
    private final int REFRESHING = 2;
    //当前状态,默认为下拉刷新
    private int currentState = PULL_DOWN_REFRESH;
    //刷新列表构造函数
    private Context context;
    //刷新监听
    private OnRefreshListener mOnRefreshListener;
    private ImageView refresh;
    private RotateAnimation animation;
    //图片向上旋转
    private Animation upAnimation;
    //图片向下旋转
    private Animation downAnimation;
    //箭头
    private ImageView row;
    //提示文本
    private TextView header_tv;
    public RefreshListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //初始化头布局
        initHeaderView();
        //滑动监听
        this.setOnScrollListener(this);
        this.context = context;
    }

    /**滚动状态改变时调用,一般用于列表视图和网格视图
     *
     * @param view
     * @param scrollState 有三种值,分别是SCROLL_STATE_IDLE,SCROLL_STATE_TOUCH_SCROLL,SCROLL_STATE_FLING
     *                    SCROLL_STATE_IDLE:当屏幕停止滚动时
     *                    SCROLL_STATE_TOUCH_SCROLL:当屏幕以触屏方式滚动并且手指还在屏幕上时
     *                    SCROLL_STATE_FLING:当用户之前滑动屏幕并抬起手指,屏幕以惯性滚动
     */
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState==SCROLL_STATE_IDLE||scrollState == SCROLL_STATE_FLING){

        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        firstVisibleItemPosition = firstVisibleItem;
    }
//    public void setOnRefreshListener(OnRefreshListener listener){
//
//    }

    public void setOnRefreshListener(OnRefreshListener listener){
        mOnRefreshListener = listener;
    }

    private void initHeaderView(){
        //头布局文件
        header = LayoutInflater.from(getContext()).inflate(R.layout.header,null);
        //测量头布局,绘制一个视图一般经过measure,layout,draw
        header.measure(0,0);
        //头布局高度
        headerViewHeight = header.getMeasuredHeight();
        //设置间隔
        header.setPadding(0,-headerViewHeight,0,0);
        //加载头布局
        this.addHeaderView(header);
        refresh = (ImageView) header.findViewById(R.id.refresh);
        row = (ImageView) header.findViewById(R.id.row);
        header_tv = (TextView) header.findViewById(R.id.header_tv);
        initAnimation();

    }
    private void initAnimation(){
        animation = new RotateAnimation(0f,360f, Animation.RELATIVE_TO_SELF,0.48f,Animation.RELATIVE_TO_SELF,0.47f);
        animation.setDuration(500);
        animation.setRepeatCount(5);

        upAnimation = new RotateAnimation(0f,180f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        upAnimation.setDuration(300);
        upAnimation.setFillAfter(true);

        downAnimation = new RotateAnimation(180f,360f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
        downAnimation.setDuration(300);
        downAnimation.setFillAfter(true);
//        refresh.setAnimation(animation);

    }

    /**
     * 触摸事件
     * @param ev
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            //手指按下
            case MotionEvent.ACTION_DOWN:
                //记录按下时y的偏移量
                downY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE://手指滑动
                //记录移动时的y值偏移
                moveY = (int) ev.getY();
                //可以看成头布局距离屏幕顶部的距离,这里除以2是控制手指滑动
                paddingTop = (moveY - downY)/2-headerViewHeight;
                if(firstVisibleItemPosition==0&&-headerViewHeight<paddingTop){//必须的条件
                    //如果paddingTop>0就说明完全显示了,但还要判断当前状态是否是下拉刷新状态,因为正在刷新状态也是完全显示
                    if(paddingTop>0&&currentState == PULL_DOWN_REFRESH){//完全显示
                        header_tv.setText("松开刷新");
                        //将当前状态置为释放刷新
                        currentState = RELEASE_REFRESH;
                        changeHeaderByViewState();
                    }else if(paddingTop<0&&currentState == RELEASE_REFRESH){//没有完全显示,currentState=RELEASE_REFRESH原因是可以先滑到完全显示后再往上滑到不完全显示
                        currentState = PULL_DOWN_REFRESH;
                        header_tv.setText("下拉刷新");
                        changeHeaderByViewState();
                    }
                    header.setPadding(0,paddingTop,0,0);
                }
                break;
            case MotionEvent.ACTION_UP:
                if(currentState == RELEASE_REFRESH){//完全显示
                    header.setPadding(0,0,0,0);
                    currentState = REFRESHING;
                    changeHeaderByViewState();
                    if (mOnRefreshListener!=null){
                        mOnRefreshListener.downPullRefresh();
                    }
                }else if(currentState == PULL_DOWN_REFRESH){//未完全显示
                    //当手指松开时,若头部未完全显示则隐藏头部
                    header.setPadding(0,-headerViewHeight,0,0);
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

    private void changeHeaderByViewState(){
        switch (currentState){
            case PULL_DOWN_REFRESH:
                row.startAnimation(downAnimation);
                break;
            case RELEASE_REFRESH:
                row.startAnimation(upAnimation);
                break;
            case REFRESHING:
                row.clearAnimation();
                row.setVisibility(View.GONE);
                header_tv.setText("正在刷新");
                refresh.clearAnimation();
                refresh.setVisibility(View.VISIBLE);
                refresh.startAnimation(animation);
                break;
        }
    }
    public void hideHeaderView(){
        header.setPadding(0,-headerViewHeight,0,0);
        refresh.setVisibility(View.GONE);
        currentState = PULL_DOWN_REFRESH;
        header_tv.setText("下拉刷新");
        row.setVisibility(View.VISIBLE);

    }
}

MainActivity.java

package com.example.yds.pulldowntest;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainActivity extends Activity implements OnRefreshListener{
    private TextView log_tv;

    private RefreshListView listView;
    private PullDownAdapter adapter;
    private Map<String,Object>map;
    List<Map<String,Object>>list = new ArrayList<>();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        log_tv = (TextView) findViewById(R.id.log_tv);
        listView = (RefreshListView) findViewById(R.id.listview);

        for (int i = 0 ;i < 5 ; i++){
            map = new HashMap<>();
            map.put("name","this "+i);
            list.add(map);
        }

        adapter = new PullDownAdapter(this,list);

        listView.setOnRefreshListener(this);
        listView.setAdapter(adapter);

        log_tv.setText(list.get(0).get("name").toString()+"this is null?"+list.get(1).get("name").toString());
    }

    @Override
    public void downPullRefresh() {
        new AsyncTask<Void,Void,Void>(){

            @Override
            protected Void doInBackground(Void... params) {
                SystemClock.sleep(2800);
                map = list.get(0);
                map.put("name","这是刷新后的数据");
                list.add(map);
                return null;
            }

            @Override
            protected void onPostExecute(Void result) {
                super.onPostExecute(result);
                adapter.notifyDataSetChanged();
                listView.hideHeaderView();
            }
        }.execute(new Void[]{});
    }
}

 

源码下载地址:

 http://download.csdn.net/detail/u013293125/9734831