自定义listview实现下拉刷新的效果

1.我们需要考虑的listview当前处于的几种状态

1)默认状态(DONE=3) 表示加载完成,刷新头部消失不见
这里写图片描述

2)正在刷新的状态(REFRESHING=2) 表示正在刷新的状态值
这里写图片描述

3)刚开始下拉但是还没有变成释放刷新的地方(PULL_To_REFRESH=1) 表示将要进行刷新
这里写图片描述

4)松开手就可以刷新的状态(RELEASE_To_REFRESH=0) 表示松开手就开始进行刷新
这里写图片描述

2.我们需要考虑listview下拉刷新时需要考虑的几个动作。
如何判断这些动作的产生?
我们可以实现ontouchevent的事件接口
1.当手指第一次触摸屏幕时,通过MotionEvent.ACTIOIN_DOWN记录下这个点击的Y轴坐标(startY)。
2.当手指移动的时候,通过MotionEvent.ACTION_MOVE做出相应的动作
这个比较复杂一点,首先你需要判断当前listview处于上面状态中的哪一个状态
1)如果处于DONE的状态,并且当前所在的位置(tempY>startY),改变当前的state状态
2)如果处于PULL_To_REFRESH状态,判断当前手指移动的距离的三分之一是不是大于头部的宽度,如果是则将当前的state改变成RELEASE_To_REFRESH,如果tempY<=startY,则将当前的状态改变成DONE。
3)如果当前处于RELEASE_To_REFRESH状态,判断当前手指移动的距离的三分之一是不是小于头部的宽度,如果是state变成PULL_To_REFRESH,如果tempY小于等于startY,则将state变成DONE.
4)如果当前处于REFRESHING状态,则不做任何处理。

3.上面的两种事情解决了,我们就需要根据手指移动的距离动态显示头部刷新框显示的大小
还需要根据state状态改变头部刷新框的显示内容

4.还需要注意的一点就是监听listview的onScroll函数,假如当前listview的firstVisibleItem等于0,才可以进行下拉刷新的动作。

PullRefreshListview的文件内容

package com.example.pullrefreshlistview;

import java.util.Date;
import java.util.zip.Inflater;

import javax.crypto.spec.IvParameterSpec;

import android.content.Context;
import android.provider.SyncStateContract.Constants;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ProgressBar;
import android.widget.TextView;

public class PullRefreshListview extends ListView implements OnScrollListener {

    LayoutInflater inflater;

    /*
     * 设置布局变量参数
     */
    int headerContentHeight;// 上拉显示框的宽度
    int state; // 当前状态
    final int REFRESHING = 2; // 正在刷新的状态值
    final int DONE = 3; // 表示加载完成
    int RATIO = 3;
    public final int RELEASE_To_REFRESH = 0; // 松开手刷新:准备从pull_to_refresh到refreshing,假如手机又上移会变成从新变成DONE

    public final int PULL_To_REFRESH = 1; // 从下拉返回到不刷新的状态值
    int startY; // 记录一下上一次记录的y坐标
    boolean isBack;
    boolean isRecored;
    OnRefreshListener listener; // 设置刷新的接口
    boolean isRefreshable = true; // 当前是够能够刷新
    private RotateAnimation animation;
    private RotateAnimation reverseAnimation;

    public void setListener(OnRefreshListener listener) {
        this.listener = listener;
    }

    /*
     * Listview头部下拉刷新的布局
     */
    private LinearLayout headerView;
    private TextView lvHeaderTipsTv;
    private TextView lvHeaderLastUpdatedTv;
    private ImageView lvHeaderArrowlv;
    private ProgressBar lvHeaderProgressBar;

    /*
     * 定义头部下拉刷新的布局高度+++
     */

    public PullRefreshListview(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        setCacheColorHint(getResources().getColor(R.color.transparent));
        inflater = LayoutInflater.from(context);
        headerView = (LinearLayout) inflater.inflate(R.layout.lv_header, null);
        lvHeaderTipsTv = (TextView) headerView
                .findViewById(R.id.lvHeaderTipsTv);
        lvHeaderLastUpdatedTv = (TextView) headerView
                .findViewById(R.id.lvHeaderLastUpdatedTv);
        lvHeaderArrowlv = (ImageView) headerView
                .findViewById(R.id.ivHeaderArrowlv);
        lvHeaderArrowlv.setMinimumHeight(70);
        lvHeaderArrowlv.setMinimumWidth(50);
        lvHeaderProgressBar = (ProgressBar) headerView
                .findViewById(R.id.ivHeaderProgressBar);
        measureView(headerView);
        headerContentHeight = headerView.getMeasuredHeight();
        Log.i("headerContentHeight", headerContentHeight+"");
        headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
        headerView.invalidate();
        addHeaderView(headerView);
        animation = new RotateAnimation(0, -180,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        animation.setInterpolator(new LinearInterpolator());
        animation.setDuration(250);
        animation.setFillAfter(true);

        reverseAnimation = new RotateAnimation(-180, 0,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        reverseAnimation.setInterpolator(new LinearInterpolator());
        reverseAnimation.setDuration(250);
        reverseAnimation.setFillAfter(true);
        setOnScrollListener(this);
        state = DONE;
        isRefreshable = false;

    }

    /**
     * 
     * @param child
     *            该函数用来估计child的width和height
     */
    private void measureView(View child) {
        ViewGroup.LayoutParams params = child.getLayoutParams();
        if (params == null) {
            params = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.WRAP_CONTENT);

        }
        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, params.width);
        int lpHeight = params.height;
        int childHeightSpec;
        if (lpHeight > 0) {
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
                    MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0,
                    MeasureSpec.UNSPECIFIED);
        }
        child.measure(childWidthSpec, childHeightSpec);

    }

    public PullRefreshListview(Context context, AttributeSet attrs,
            int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    public PullRefreshListview(Context context, AttributeSet attrs,
            int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    public PullRefreshListview(Context context) {
        super(context);
        init(context);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (isRefreshable) {
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (!isRecored) {
                    isRecored = true;
                    startY = (int) ev.getY();
                    Log.i("startY", startY+"");
                }
                break;

            case MotionEvent.ACTION_UP:
                if (state != REFRESHING) {
                    if (state == PULL_To_REFRESH) {
                        state = DONE;
                        changeHeaderViewByState();
                    }
                    if (state == RELEASE_To_REFRESH) {
                        state = REFRESHING;
                        changeHeaderViewByState();
                        onLvRefresh();
                    }
                }
                isRecored = false;
                isBack = false;
                break;

            case MotionEvent.ACTION_MOVE:
                int tempY = (int) ev.getY();
                if (!isRecored) {
                    isRecored = true;
                    startY = tempY;
                }
                if ( state != REFRESHING) {
                    if (state == RELEASE_To_REFRESH) {
                        setSelection(0);
                        if (((tempY - startY) / RATIO < headerContentHeight)
                                && (tempY - startY) > 0) {
                            state = PULL_To_REFRESH;
                            changeHeaderViewByState();
                        } else if ((tempY - startY) <= 0) {
                            state = DONE;
                            changeHeaderViewByState();
                        }
                    }
                    if(state==PULL_To_REFRESH)
                    {
                        setSelection(0);
                        if((tempY-startY)/RATIO>=headerContentHeight)
                        {
                            state=RELEASE_To_REFRESH;
                            isBack=true;
                            changeHeaderViewByState();
                        }else if(tempY-startY<=0)
                        {
                            state=DONE;
                            changeHeaderViewByState();
                        }
                    }

                    // done状态下
                    if (state == DONE) {
                        if (tempY - startY > 0) {
                            state = PULL_To_REFRESH;
                            changeHeaderViewByState();
                        }
                    }
                    // 更新headView的size
                    if (state == PULL_To_REFRESH) {
                        headerView.setPadding(0, -1 * headerContentHeight
                                + (tempY - startY) / RATIO, 0, 0);

                    }
                    // 更新headView的paddingTop
                    if (state == RELEASE_To_REFRESH) {
                        headerView.setPadding(0, (tempY - startY) / RATIO
                                - headerContentHeight, 0, 0);
                    }           
                    }

                break;
            }
        }
        return super.onTouchEvent(ev);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        if (firstVisibleItem == 0)
            isRefreshable = true;
        else
            isRefreshable = false;

    }

    interface OnRefreshListener {
        void onRefresh();
    }

    public void onRefreshComplete() {
        state = DONE;
        lvHeaderLastUpdatedTv.setText("最新更新:" + new Date().toLocaleString());
        headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
    }

    public void onLvRefresh() {
        if (listener != null)
            listener.onRefresh();
    }

    public void changeHeaderViewByState() {
        switch (state) {
        case RELEASE_To_REFRESH: // 表示当前的手势是下拉但是还没有释放,当前手还放在屏幕上
            lvHeaderArrowlv.setVisibility(View.VISIBLE);
            lvHeaderProgressBar.setVisibility(View.GONE);
            lvHeaderTipsTv.setVisibility(View.VISIBLE);
            lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
            lvHeaderArrowlv.clearAnimation();
            lvHeaderArrowlv.startAnimation(animation);
            lvHeaderTipsTv.setText("松开刷新");
            break;

        case PULL_To_REFRESH:
            lvHeaderProgressBar.setVisibility(View.GONE);
            lvHeaderTipsTv.setVisibility(View.VISIBLE);
            lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
            lvHeaderArrowlv.clearAnimation();
            lvHeaderArrowlv.setVisibility(View.VISIBLE);
            if (isBack) {// 这里表示该状态是从RELEASE_REFRESH状态这个状态
                isBack = false;
                lvHeaderArrowlv.clearAnimation();
                lvHeaderArrowlv.startAnimation(reverseAnimation);
                lvHeaderTipsTv.setText("下拉刷新");
            } else {
                lvHeaderTipsTv.setText("下拉刷新");
            }
            break;

        case REFRESHING:
            headerView.setPadding(0, 0, 0, 0);
            lvHeaderProgressBar.setVisibility(View.VISIBLE);
            lvHeaderArrowlv.clearAnimation();
            lvHeaderArrowlv.setVisibility(View.GONE);
            lvHeaderTipsTv.setText("正在刷新...");
            lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
            break;

        case DONE:
            headerView.setPadding(0, -1 * headerContentHeight, 0, 0);
            lvHeaderProgressBar.setVisibility(View.GONE);
            lvHeaderArrowlv.clearAnimation();
            lvHeaderArrowlv.setImageResource(R.drawable.arrow);
            lvHeaderTipsTv.setText("下拉刷新");
            lvHeaderLastUpdatedTv.setVisibility(View.VISIBLE);
            break;

        }
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        // TODO Auto-generated method stub
        onRefreshComplete();
        super.setAdapter(adapter);
    }

}

listview的适配器
LvAdapter.java

public class LvAdapter extends BaseAdapter {
    private List<String> list;
    private Context context;

    public LvAdapter(List<String> list, Context context) {
        this.list = list;
        this.context = context;
    }

    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int position) {
        return list.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TextView tv = new TextView(context.getApplicationContext());
        tv.setText(list.get(position));
        return tv;
    }

}

Mainactivity.java

package com.example.pullrefreshlistview;

import java.util.ArrayList;
import java.util.List;

import com.example.pullrefreshlistview.PullRefreshListview.OnRefreshListener;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {
    private TextView loadMoreTv;
    private List<String> list;
    private PullRefreshListview lv;
    private LvAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv = (PullRefreshListview) findViewById(R.id.lv);
        list = new ArrayList<String>();
        list.add("新新闻");
        list.add("loonggg");
        list.add("samon");
        list.add("我们都是开发者");
        list.add("我们都是开发者");
        list.add("我们都是开发者");
        list.add("我们都是开发者");
        list.add("我们都是开发者");
        list.add("我们都是开发者");
        list.add("我们都是开发者");
        list.add("我们都是开发者");

        adapter = new LvAdapter(list, this);
        lv.setAdapter(adapter);

        lv.setListener(new OnRefreshListener() {

            @Override
            public void onRefresh() {
                // TODO Auto-generated method stub
                new AsyncTask<Void, Void, Void>() {
                    protected Void doInBackground(Void... params) {
                        try {
                            Thread.sleep(1000);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                        for (int i = 0; i < 20; i++) {
                            list.add("刷新后添加的内容");
                        }

                        return null;
                    }

                    @Override
                    protected void onPostExecute(Void result) {
                        adapter.notifyDataSetChanged();
                        lv.onRefreshComplete();
                    }
                }.execute(null, null, null);
            }
        });
    }
}

大体的实现就是这样了,如果需要下载源代码,可以到这里下载:https://github.com/gxl1240779189/PullRefreshListview.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值