ListView下拉刷新和上拉加载原理

ListView的下拉刷新逻辑:
一、获取ListView的头布局的高度并通过给头布局setPading方法,将头布局隐藏
二、重写ListView的onTouchEvent方法计算出滑动的偏移量dy
三、通过比较偏移量和头布局的高度,进行UI的修改
ListView上拉加载逻辑:
一、获取ListView的脚布局的高度并通过setPading方法,将头布局隐藏
二、调用ListView的setOnScrollListener方法,重写两个方法
1、onScrollStateChanged
当滑动状态是静止状态,并且最后一个条目是脚布局
的时候,显示脚布局,然后加载下一页数据,并修改UI

2、onScroll

接下来直接看代码:

public class RefreshListVeiw extends ListView implements AbsListView.OnScrollListener {
    public static final int STATE_PULL_TO_REFRESH    = 0;//下拉刷新
    public static final int STATE_RELEASE_TO_REFRESH = 1;//松开刷新
    public static final int STATE_REFRESHING         = 2;//正在刷新
    //当前默认状态为下拉刷新
    private             int mCurrentState            = STATE_PULL_TO_REFRESH;
    private int             mMeasuredHeight;
    private float           startY;
    private View            headerView;
    private ImageView       ivArrow;
    private TextView        tvStatus;
    private ProgressBar     pbLoading;
    private RotateAnimation upAnimation;
    private RotateAnimation downAnimation;
    private View            footView;
    private int             footViewHight;

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

    public RefreshListVeiw(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public RefreshListVeiw(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initHeaderView(context);
        initFootView(context);
        initAnimation();
    }

    private void initHeaderView(Context context) {
        headerView = View.inflate(context, R.layout.view_header, null);
        ivArrow = (ImageView) headerView.findViewById(R.id.ivArrow);
        tvStatus = (TextView) headerView.findViewById(R.id.tvStatus);
        pbLoading = (ProgressBar) headerView.findViewById(R.id.pbLoading);
        this.addHeaderView(headerView);
        //padding值能改变控件的大小
        //获取头布局的高度
        /**
         * View的生命周期和Activity的生命周期
         * 并不是同步的,如果Activity的生命周期中
         * View还没有测量完毕
         */
        headerView.measure(0, 0);
        mMeasuredHeight = headerView.getMeasuredHeight();
        headerView.setPadding(0, -mMeasuredHeight, 0, 0);
    }

    /**
     * 想要在listView向下滑动的时候,将头布局
     * 一点一点显示出来,这个时候就要响应ListView
     * 的滑动事件
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                startY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveY = ev.getY();
                float dy = moveY - startY;
                /**
                 * 此时ListView第一个可见条目就是
                 * 头布局,头布局此时虽然不可见,
                 * 但是相当于一条线,依然是ListView
                 * 的第一个可见条目
                 */
                int firstVisiblePosition = getFirstVisiblePosition();
                //如果第一个可见条目是头布局,并且,是向下滑动的时候
                if (firstVisiblePosition == 0 && dy > 0) {
                    //如果当前状态为正在刷新,则不需要再改变布局的高度了
                    if (mCurrentState == STATE_REFRESHING) {
                        break;
                    }
                    //慢慢显示出来
                    int paddingTop = (int) (dy - mMeasuredHeight);
                    headerView.setPadding(0, paddingTop, 0, 0);

                    if (paddingTop < 0) { //下拉刷新状态
                        mCurrentState = STATE_PULL_TO_REFRESH;
                        refreshState();
                    } else { //松开刷新
                        mCurrentState = STATE_RELEASE_TO_REFRESH;
                        refreshState();
                    }

                    return true;//代表消费了事件
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mCurrentState == STATE_PULL_TO_REFRESH) {
                    //隐藏头布局
                    headerView.setPadding(0, -mMeasuredHeight, 0, 0);
                } else if (mCurrentState == STATE_RELEASE_TO_REFRESH) {
                    //更新状态
                    mCurrentState = STATE_REFRESHING;
                    refreshState();
                    //让头部局完全显示
                    headerView.setPadding(0, 0, 0, 0);
                    //加载数据
                    notifyOnRefresh();
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

    private void refreshState() {
        switch (mCurrentState) {
            case STATE_PULL_TO_REFRESH:
                //设置为GONE会影响布局显示的情况
                pbLoading.setVisibility(INVISIBLE);
                ivArrow.setVisibility(VISIBLE);
                tvStatus.setText("下拉刷新");
                ivArrow.setAnimation(upAnimation);
                break;
            case STATE_RELEASE_TO_REFRESH:
                pbLoading.setVisibility(INVISIBLE);
                ivArrow.setVisibility(VISIBLE);
                ivArrow.setAnimation(downAnimation);
                tvStatus.setText("松开刷新");
                break;
            case STATE_REFRESHING:
                pbLoading.setVisibility(VISIBLE);
                ivArrow.setVisibility(INVISIBLE);
                //需要把ivArrow的动画移除,才能把ivArrow隐藏起来
                ivArrow.clearAnimation();
                tvStatus.setText("正在刷新");
                break;
        }
    }

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


        downAnimation = new RotateAnimation(-180, 0,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        downAnimation.setDuration(200);
        downAnimation.setFillAfter(true);
    }

    private boolean isLoadingMore = false;

    //当滚动状态发生改变的时候,发生的回调
    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE && !isLoadingMore) {
            int lastVisiblePosition = getLastVisiblePosition();
            if (lastVisiblePosition == getCount() - 1) {
                // getCount()-1是那一条脚布局的线
                //显示脚布局
                footView.setPadding(0, 0, 0, 0);
                //需要让脚布局自己显示出来
                setSelection(getCount() - 1);
                isLoadingMore = true;
                //加载下一页数据
                notifyOnLoadMore();
            }
        }
    }

    //这个滚动过程都会进行的回调
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

    }

    //定义回调接口
    public interface onRefreshListener {
        void onRefresh();

        void onLoadMore();
    }

    //保存接口引用
    private onRefreshListener mListener;

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

    private void notifyOnRefresh() {
        if (mListener != null) {
            mListener.onRefresh();
        }
    }

    private void notifyOnLoadMore() {
        if (mListener != null) {
            mListener.onLoadMore();
        }
    }

    //数据刷新后需要隐藏headerView,并改变状态
    public void onRefreshComplete() {
        headerView.setPadding(0, -mMeasuredHeight, 0, 0);
        mCurrentState = STATE_PULL_TO_REFRESH;
        pbLoading.setVisibility(INVISIBLE);
        ivArrow.setVisibility(VISIBLE);
        tvStatus.setText("下拉刷新");
    }


    private void initFootView(Context context) {
        footView = View.inflate(context, R.layout.view_footer, null);
        footView.measure(0, 0);
        footViewHight = footView.getMeasuredHeight();
        footView.setPadding(0, -footViewHight, 0, 0);
        this.addFooterView(footView);
        this.setOnScrollListener(this);
    }

    public void onLoadMoreComplete() {
        isLoadingMore = false;
        footView.setPadding(0, -footViewHight, 0, 0);
    }

}

public class MainActivity extends AppCompatActivity {

    private RefreshListVeiw mListView;
    private ArrayList<NewsData> mList = new ArrayList<>();
    private MainActivity mContent;
    private MyAdapter    myAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContent = MainActivity.this;
        initData();
        mListView = (RefreshListVeiw) findViewById(R.id.listView);
        myAdapter = new MyAdapter();
        mListView.setAdapter(myAdapter);
        mListView.setOnRefreshListener(new RefreshListVeiw.onRefreshListener() {
            @Override
            public void onRefresh() {
                initData();
                myAdapter.notifyDataSetChanged();
                //加载数据成功后,隐藏布局
                mListView.onRefreshComplete();
            }

            @Override
            public void onLoadMore() {
                initData();
                myAdapter.notifyDataSetChanged();
                mListView.onLoadMoreComplete();
            }
        });
    }

    private int index = 1;

    private void initData() {

        for (int i = 0; i < 10; i++) {
            NewsData newsData = new NewsData();
            newsData.content = "我是第" + index + "item";
            index++;
            mList.add(newsData);
        }
    }


    class MyAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return mList.size();
        }

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

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

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if (convertView == null) {
                convertView = View.inflate(mContent, R.layout.view_item_listview, null);
                holder = new ViewHolder();
                holder.tvContent = (TextView) convertView.findViewById(R.id.tvContent);
                convertView.setTag(holder);
            }
            holder = (ViewHolder) convertView.getTag();
            holder.tvContent.setText(mList.get(position).content);
            return convertView;
        }

    }

    static class ViewHolder {
        TextView tvContent;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SunnyRivers

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值