ListView上拉加载和下拉刷新多种实现方式

本文详述了ListView实现上拉加载和下拉刷新的多种方法,包括自定义View、PullToRefresh库、Ultra-Pull-To-Refresh库和SwipeToRefreshLayout。文章通过代码示例和关键逻辑讲解,帮助开发者了解并实现这些功能。
摘要由CSDN通过智能技术生成

ListView上拉加载和下拉刷新多种实现方式

该篇为ListView下拉刷新和上拉加载实现的各种方法大合集。可能在具体的细节逻辑上处理不太到位,但基本上完成逻辑的实现。细节方面,个人可以根据自己的需求进行完善。

该博客将以四种思路来完成下拉刷新和上拉加载

  • 自定义View实现上拉加载和下拉刷新
  • 使用PullToRefresh 实现上拉加载和下拉刷新
  • 使用Ultra-Pull-To-Refresh实现上拉加载和下拉刷新
  • 使用SwipeToRefreshLayout实现上拉加载和下拉刷新

如果你对ListView不够熟悉,欢迎看我之前的博客 ListView使用总结

自定义View实现上拉加载和下拉刷新

该方法,我们通过完全自定义的方式实现,不添加任何依赖库和jar包。纯原生。

首先看一下我们实现的效果

这里写图片描述

实现的关键点:

  • ListView添加头布局和底布局。
  • 通过改变头布局的paddingTop值,来控制控件的显示和隐藏
  • 根据我们滑动的状态,动态修改头部布局和底部布局。

看一下代码:

public class CustomRefreshListView extends ListView implements OnScrollListener{
   

    /**
     * 头布局
     */
    private View headerView;

    /**
     * 头部布局的高度
     */
    private int headerViewHeight;

    /**
     * 头部旋转的图片
     */
    private ImageView iv_arrow;

    /**
     * 头部下拉刷新时状态的描述
     */
    private TextView tv_state;

    /**
     * 下拉刷新时间的显示控件
     */
    private TextView tv_time;


    /**
     * 底部布局
     */
    private View footerView;

    /**
     * 底部旋转progressbar
     */
    private ProgressBar pb_rotate;


    /**
     * 底部布局的高度
     */
    private int footerViewHeight;


    /**
     * 按下时的Y坐标
     */
    private int downY;

    private final int PULL_REFRESH = 0;//下拉刷新的状态
    private final int RELEASE_REFRESH = 1;//松开刷新的状态
    private final int REFRESHING = 2;//正在刷新的状态

    /**
     * 当前下拉刷新处于的状态
     */
    private int currentState = PULL_REFRESH;

    /**
     * 头部布局在下拉刷新改变时,图标的动画
     */
    private RotateAnimation upAnimation,downAnimation;

    /**
     * 当前是否在加载数据
     */
    private boolean isLoadingMore = false;

    public CustomRefreshListView(Context context) {
        this(context,null);
    }

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

    private void init(){
        //设置滑动监听
        setOnScrollListener(this);
        //初始化头布局
        initHeaderView();
        //初始化头布局中图标的旋转动画
        initRotateAnimation();
        //初始化为尾布局
        initFooterView();
    }


    /**
     * 初始化headerView
     */
    private void initHeaderView() {
        headerView = View.inflate(getContext(), R.layout.head_custom_listview, null);
        iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);
        pb_rotate = (ProgressBar) headerView.findViewById(R.id.pb_rotate);
        tv_state = (TextView) headerView.findViewById(R.id.tv_state);
        tv_time = (TextView) headerView.findViewById(R.id.tv_time);

        //测量headView的高度
        headerView.measure(0, 0);
        //获取高度,并保存
        headerViewHeight = headerView.getMeasuredHeight();
        //设置paddingTop = -headerViewHeight;这样,该控件被隐藏
        headerView.setPadding(0, -headerViewHeight, 0, 0);
        //添加头布局
        addHeaderView(headerView);
    }

    /**
     * 初始化旋转动画
     */
    private void initRotateAnimation() {

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

        downAnimation = new RotateAnimation(-180, -360, 
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        downAnimation.setDuration(300);
        downAnimation.setFillAfter(true);
    }

    //初始化底布局,与头布局同理
    private void initFooterView() {
        footerView = View.inflate(getContext(), R.layout.foot_custom_listview, null);
        footerView.measure(0, 0);
        footerViewHeight = footerView.getMeasuredHeight();
        footerView.setPadding(0, -footerViewHeight, 0, 0);
        addFooterView(footerView);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //获取按下时y坐标
            downY = (int) ev.getY();
            break;
        case MotionEvent.ACTION_MOVE:

            if(currentState==REFRESHING){
                //如果当前处在滑动状态,则不做处理
                break;
            }
            //手指滑动偏移量
            int deltaY = (int) (ev.getY() - downY);

            //获取新的padding值
            int paddingTop = -headerViewHeight + deltaY;
            if(paddingTop>-headerViewHeight && getFirstVisiblePosition()==0){
                //向下滑,且处于顶部,设置padding值,该方法实现了顶布局慢慢滑动显现
                headerView.setPadding(0, paddingTop, 0, 0);

                if(paddingTop>=0 && currentState==PULL_REFRESH){
                    //从下拉刷新进入松开刷新状态
                    currentState = RELEASE_REFRESH;
                    //刷新头布局
                    refreshHeaderView();
                }else if (paddingTop<0 && currentState==RELEASE_REFRESH) {
                    //进入下拉刷新状态
                    currentState = PULL_REFRESH;
                    refreshHeaderView();
                }


                return true;//拦截TouchMove,不让listview处理该次move事件,会造成listview无法滑动
            }


            break;
        case MotionEvent.ACTION_UP:
            if(currentState==PULL_REFRESH){
                //仍处于下拉刷新状态,未滑动一定距离,不加载数据,隐藏headView
                headerView.setPadding(0, -headerViewHeight, 0, 0);
            }else if (currentState==RELEASE_REFRESH) {
                //滑倒一定距离,显示无padding值得headcView
                headerView.setPadding(0, 0, 0, 0);
                //设置状态为刷新
                currentState = REFRESHING;

                //刷新头部布局
                refreshHeaderView();

                if(listener!=null){
                    //接口回调加载数据
                    listener.onPullRefresh();
                }
            }
            break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 根据currentState来更新headerView
     */
    private void refreshHeaderView(){
        switch (currentState) {
        case PULL_REFRESH:
            tv_state.setText(
  • 9
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值