android 开发笔记 自定义可下拉刷新上拉加载的ListView

后续可以根据自己需求更改头布局和尾布局,不多说直接上代码

这是我们自定义的ListView

public class MyPullToRefreshListView extends ListView implements AbsListView.OnScrollListener,ValueAnimator.AnimatorUpdateListener {

    private int index = 0;//当前listview处于的位置 0代表头部,1代表中间,2代表尾部
    private View headerView,footerView;
    private TextView headerTv,footerTv;

    private int mode = 0;//0代表完成  1代表下拉刷新  2代表释放立即刷新  3代表正在刷新 4代表上拉加载  5代表释放立即加载  6代表正在加载
    private final int DONE = 0;
    private final int DOWN_TO_REFRESH = 1;
    private final int RELEASE_TO_REFRESH = 2;
    private final int REFRESHING = 3;

    private final int UP_TO_LOAD = 4;
    private final int RELEASE_TO_LOAD = 5;
    private final int LOADING = 6;

    private ValueAnimator animator;

    private PointF p;

    private int layoutHeight; //头的高度
    private int lineHeight = 50; //释放刷新的高度
    private int rote = 3;//设置刷新的距离比较缓慢

    //加载和刷新的监听事件
    public interface OnRefreshListener{

        //正在加载
        void onLoad();

        //正在刷新
        void onRefresh();
    }

    private OnRefreshListener listener;

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

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

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

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                //按下
                p = new PointF();
                p.x = ev.getX();
                p.y = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                //获取现在的位置
                PointF m = new PointF();
                m.x = ev.getX();
                m.y = ev.getY();

                int disx = (int) (m.y - p.y)/rote;
                //如果在头部
                if(index == 0){

                    if(disx<=0){
                        return super.dispatchTouchEvent(ev);//事件向下分发
                    }

                    //处理下拉的操作,如果正在刷新数据或者正在加载,就不处理
                    if(mode != REFRESHING && mode != LOADING){
                        //设置现在的状态是下拉刷新
                        mode = DOWN_TO_REFRESH;
                        selectMode();
                        //慢慢地看到头
                        headerView.setPadding(0,-layoutHeight+disx,0,0);

                        //判断是否达到临界值
                        if(-layoutHeight+disx >=lineHeight){
                            //设置现在状态是释放立即刷新
                            mode = RELEASE_TO_REFRESH;
                            selectMode();
                        }

                        return true;//事件在此进行处理
                    }
                }

                //尾部
                else if(index == 2){

                    if(disx >= 0){
                        return super.dispatchTouchEvent(ev);//事件向下进行分发
                    }

                    //处理上拉的操作,如果正在刷新数据或者正在加载,就不处理
                    if(mode != REFRESHING && mode != LOADING){

                        //将listview定位到尾部
                        ListAdapter adapter = getAdapter();
                        setSelection(adapter.getCount()-1);
                        //设置现在的状态上拉加载
                        mode = UP_TO_LOAD;
                        selectMode();
                        disx = Math.abs(disx);
                        //慢慢地看到尾部
                        footerView.setPadding(0,0,0,-layoutHeight+disx);
                        //到达临界值
                        if(-layoutHeight+disx >= lineHeight){
                            //设置现在的状态释放立即加载
                            mode = RELEASE_TO_LOAD;
                            selectMode();
                        }

                        return  true;//事件在此进行处理
                    }
                }else{

                    //改变开始的位置
                    p = m;
                }

                break;
            case MotionEvent.ACTION_UP:

                //如果不是正在加载或者正在刷新
                if(mode != REFRESHING && mode != LOADING){

                    //判断是否已经到达临界点
                    if(mode == RELEASE_TO_REFRESH){ //释放立即刷新
                        //显示正在刷新
                        mode = REFRESHING;
                        selectMode();
                        if(listener!=null){
                            listener.onRefresh();
                        }
                        animator.setIntValues(headerView.getPaddingTop(),0);
                        animator.start();
                    }else if(mode == RELEASE_TO_LOAD){ //释放立即加载
                        mode = LOADING;
                        selectMode();
                        if(listener!=null){
                            listener.onLoad();
                        }
                        animator.setIntValues(footerView.getPaddingBottom(),0);
                        animator.start();

                    }else if(mode == DOWN_TO_REFRESH){ //下拉刷新
                        //隐藏头部
                        animator.setIntValues(headerView.getPaddingTop(),-layoutHeight);
                        animator.start();
                    }else if(mode == UP_TO_LOAD){  //上拉加载
                        //隐藏尾部
                        animator.setIntValues(footerView.getPaddingBottom(),-layoutHeight);
                        animator.start();
                    }
                }

                break;
        }

        return super.dispatchTouchEvent(ev); //事件向下分发
    }

    //设置刷新完成
    public void complete(){

        animator.setIntValues(0,-layoutHeight);
        animator.start();
        //设置完成
        mode = DONE;
        selectMode();
    }

    //根据状态设置Listview的位置
    public void selectMode(){
        switch (mode){
            case DONE:
                //隐藏头和尾
                headerView.setPadding(0,-layoutHeight,0,0);
                footerView.setPadding(0,0,0,-layoutHeight);
                break;
            case DOWN_TO_REFRESH:
                //下拉刷新
                headerTv.setText(R.string.DownToRefresh);
                break;
            case UP_TO_LOAD:
                //上拉加载
                footerTv.setText(R.string.UpToLoad);
                break;
            case RELEASE_TO_REFRESH:
                //释放立即刷新
                headerTv.setText(R.string.UpToRefresh);
                break;
            case RELEASE_TO_LOAD:
                //释放立即加载
                footerTv.setText(R.string.DownToLoad);
                break;
            case REFRESHING:
                //正在刷新
                headerTv.setText(R.string.Refreshing);
                break;
            case LOADING:
                //正在加载
                footerTv.setText(R.string.Loading);
                break;
        }
    }

    //初始化信息
    public void init(){

        //获取头和尾的高度
        layoutHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60, getContext().getResources().getDisplayMetrics());

        //设置listview的滑动监听事件
        setOnScrollListener(this);

        //加头和加尾部
        headerView = View.inflate(getContext(), R.layout.refresh,null);
        footerView = View.inflate(getContext(),R.layout.refresh,null);


        headerTv = (TextView) headerView.findViewById(R.id.refresh_tv);
        footerTv = (TextView) footerView.findViewById(R.id.refresh_tv);

        //设置头部隐藏
        //设置尾部隐藏
        selectMode();
        addHeaderView(headerView);
        addFooterView(footerView);

        animator = new ValueAnimator();
        animator.setDuration(500);
        animator.addUpdateListener(this);

    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    /**
     *
     * @param view
     * @param firstVisibleItem 当前可见的第一个item的位置
     * @param visibleItemCount 当前可见item的总个数
     * @param totalItemCount //listview的总个数
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

        if(firstVisibleItem == 0){
            //处于头部
            index = 0;
        }else if(firstVisibleItem + visibleItemCount == totalItemCount){
            //处于尾部
            index = 2;
        }else{
            //处于中间
            index = 1;
        }
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {

        //改变header的pading
        if(mode == REFRESHING || mode == DOWN_TO_REFRESH){
            headerView.setPadding(0,(Integer)animation.getAnimatedValue(),0,0);
        }

        if(mode == LOADING || mode == UP_TO_LOAD){
            footerView.setPadding(0,0,0,(Integer)animation.getAnimatedValue());
        }
    }
}

下面是头和尾的布局文件,根据需求更改

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

    <TextView
        android:id="@+id/refresh_tv"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:textSize="22sp"
        android:text="@string/Done"
        android:gravity="center"/>

</LinearLayout>

Activity调用代码

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (MyPullToRefreshListView) findViewById(R.id.mylist);
        datas = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            datas.add("测试数据"+i);
        }

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,datas);
        listView.setAdapter(adapter);

        listView.setOnRefreshListener(new MyPullToRefreshListView.OnRefreshListener() {
            @Override
            public void onLoad() {

                //模拟加载数据
                listView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        listView.complete();
                    }
                },2000);
            }

            @Override
            public void onRefresh() {

                //模拟刷新数据
                listView.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        listView.complete();
                    }
                },2000);
            }
        });
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值