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;}
}

ListView下拉刷新和上拉加载原理相关推荐

  1. android--------自定义控件ListView实现下拉刷新和上拉加载

    开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,为了方便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能. Android下拉刷新可以分为两种情况: 1.获取 ...

  2. Flutter如何实现下拉刷新和上拉加载更多

    效果 下拉刷新 如果实现下拉刷新,必须借助RefreshIndicator,在listview外面包裹一层RefreshIndicator,然后在RefreshIndicator里面实现onRefre ...

  3. Android下拉刷新和上拉加载更多

    Android下拉刷新和上拉加载更多 下拉刷新 通过android系统提供的组件:SwipeRefreshLayout 一.基本使用 1 xml中 添加 SwipeRefreshLayout 组件 该 ...

  4. 使用SwipeRefreshLayout和RecyclerView实现仿“简书”下拉刷新和上拉加载更多

    原文地址: http://blog.csdn.net/leoleohan/article/details/50989549/ 一.概述 我们公司目前开发的所有Android APP都是遵循iOS风格设 ...

  5. android pulldown view,Android控件PullRefreshViewGroup实现下拉刷新和上拉加载

    本文实例为大家分享了Android实现下拉刷新和上拉加载更多的具体代码,供大家参考,具体内容如下 先分享下源码:Android实现下拉刷新和上拉加载更多 实现思路:由PullRefreshViewGr ...

  6. 微信小程序下拉刷新和上拉加载

    效果图 微信小程序实现下拉刷新和上拉加载有2中方法 1 用系统自带的 个人感觉特别简单 2 使用scroll-view  实现, scroll-view 里面有2个属性是滑动到顶部以及到底部如下 其实 ...

  7. php mescroll,mescroll下拉刷新和上拉加载js框架

    插件描述:mescroll精致的下拉刷新和上拉加载js框架.原生js, 支持vue, 不依赖jquery, zepto, 比iScroll,dropload精简强大; 一套代码多端运行: 完美运行于a ...

  8. 【好程序员笔记分享】——下拉刷新和上拉加载更多

    -iOS培训,iOS学习-------型技术博客.期待与您交流!------------ iOS学习之路--下拉刷新和上拉加载更多 简介 本文中笔者将和大家分享应用app中常用到的表单内容的下拉刷新和 ...

  9. vant实现下拉刷新和上拉加载_微信小程序 - 实现下拉刷新、上拉加载

    在小程序开发中使用下拉刷新和上拉加载非常多,比如常用的展示型首页,而实现这个功能有两种形式,第一种是使用 scroll-view 组件,第二种是不使用 scroll-view 组件而让整个页面刷新,那 ...

  10. 入门微信小程序(含实战) [第九篇] -- 下拉刷新和上拉加载

    下拉刷新和上拉加载是两个独立又密切联系的功能,上拉加载需要服务器端有分页机制,而下拉刷新除了重新获取信息外还要对之前的状态和页码进行初始化. 一个一个来吧. 服务器端分页 其实yii2早就已经为我们准 ...

最新文章

  1. Java IO流--练习
  2. JDK11的新特性:HTTP API和reactive streams
  3. openmv串口数据 串口助手_STM32 串口接收不定长数据 STM32 USART空闲检测中断
  4. 用c语言构建二叉树(重点)
  5. Java日常错误及需要注意细节,持续更新......
  6. Tensorflow 2 循环神经网络 GRU 豆瓣IMDB影评数据集训练模型
  7. CF429E Points and Segments
  8. ubuntu18.04 ROS安装配置及常见问题得解决
  9. MySQL服务端恶意读取客户端文件漏洞 (DDCTF2019和国赛均涉及到这个漏洞)
  10. 8.4文件系统的管理与挂载2
  11. ACM投稿ccs concepts查询The ACM Computing Classification System
  12. 通过vba代码将word转换为PDF
  13. 离散中多重组合是指_大学离散数学复习试题
  14. 如何使用python将数据写入txt文件
  15. 注解之注解的基本概念
  16. Springboot项目架构设计
  17. mysql的column是什么意思_column意思 数据库中的column是什么意思
  18. win10磁盘分区图文教程
  19. 如何使用装饰设计模式读取指定路径下的纯文本文件的实现代码
  20. 2020长三角(上海)区块链应用创新大赛复赛评审圆满结束

热门文章

  1. 取消文件与svn服务器的关联
  2. HDU 4763 Theme Section ( KMP )
  3. Java:多线程,线程池,用Executors静态工厂生成常用线程池
  4. C#中字符串转换成枚举类型的方法
  5. Freeswitch mod 安装
  6. Linux运维课程 第一阶段 重难点摘要(一)网络基础
  7. Quartz.NET实现作业调度
  8. java性能、代码优化
  9. TCP/IP Protocol Fundamentals Explained with a Diagram
  10. mysql服务的注册,启动、停止、注销。 [delphi代码实现]