Android中Listview下拉刷新和上拉加载更多的多种实现方案

listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明。

方案一:添加头布局和脚布局

android系统为listview提供了addfootview和addheadview两个API。这样可以直接自定义一个View,以添加视图的形式实现下来刷新和上拉加载。

实现步骤   

1、创建一个类继承ListView:class PullToRefreshListView extends ListView;

2、在构造方法中添加HeadView:addHeaderView(headView);

3、获取HeadView的高。测量控件的高可以有两方法getMeasuredHeight和getHeight,getMeasuredHeight()在onMeasure方法执行之后才能获取到;getHeight()  在onLayout方法执行之后才能获取到值;

4、显示和隐藏headView,通过setpadding实现,当向下滑,且第一条可见item是第0条的时候才需要设置HeadView的paddingTop来显示HeadView。

显示:headView.setPadding(0,0,0,0);

隐藏:headView.setPadding(0,-headViewHeight,0,0);

5、下拉刷新三种状态的判断,移动的时候,当paddingTop < 0 的时候,说明HeadView没有完全显示出来,进入下拉刷新状态;移动的时候,当paddingTop >= 0 的时候,   说明HeadView已经完全显示出来了,进入松开以新状态;手指抬起的时候,且当前状态是松开刷新状态的时候,进入正在刷新状态; 当已经是“正在刷新”状态时,   则不允许再做”下拉刷新”和”松开刷新”的操作了,在Move事件中加入判断,如果已经是正在刷新状态了,则不处理下拉的操作了。

6、下拉箭头的转动。下拉刷新是向下,松开刷新时向上。旋转动画通过属性动画实现。隐藏箭头的时候要清除动画:iv_arrow.clearAnimation();  如果不隐藏动画效果,设置View.GONE之后还是看得见的。

7、HeadView显示时,当手指松开时的处理,松开时如果是“正在刷新”状态,则把headVie完全显示;松开时如果是“下拉刷新”状态,则把HeadView完全隐藏

8、增加FooterView:addFooterView(footerView)。当ListView处于空闲状态,并且最后一条可见item是ListView中的最后一条数据时显示footview,   footerView显示出来后,ListView不会自动上滑把FooterView显示出来的,所以需要手动设置:setSelection(getCount() - 1);即选中最后一条。

9、增加回调监听器。当ListView处于刷新状态的时候会调用onRefreshing()方法;当ListView处于加载更多的时候会调用onLoadMore()。加载完成后通知控件加载完成。

具体实现:

import com.itheima.pulltorefreshlistview.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
public class PullToRefreshListView extends ListView {
  private View headerView;
  private float downY;
  private int headerViewHeight;
  /** 状态:下拉刷新 */
  private static final int STATE_PULL_TO_REFRESH = 0;
  /** 状态:松开刷新 */
  private static final int STATE_RELEASE_REFRESH = 1;
  /** 状态:正在刷新 */
  private static final int STATE_REFRESHING = 2;
  /** 当前状态 */
  private int currentState = STATE_PULL_TO_REFRESH;  // 默认是下拉刷新状态
  private ImageView iv_arrow;
  private ProgressBar progress_bar;
  private TextView tv_state;
  private RotateAnimation upAnim;
  private RotateAnimation downAnim;
  private OnRefreshingListener mOnRefreshingListener;
  private View footerView;
  private int footerViewHeight;
  /** 正在加载更多 */
  private boolean loadingMore;
  public PullToRefreshListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initHeaderView();
    initFooterView();
  }
  private void initHeaderView() {
    headerView = View.inflate(getContext(), R.layout.header_view, null);
    iv_arrow = (ImageView) headerView.findViewById(R.id.iv_arrow);
    progress_bar = (ProgressBar) headerView.findViewById(R.id.progress_bar);
    showRefreshingProgressBar(false);
    tv_state = (TextView) headerView.findViewById(R.id.tv_state);
    headerView.measure(0, 0);  // 主动触发测量,mesure内部会调用onMeasure
    headerViewHeight = headerView.getMeasuredHeight();
    hideHeaderView();
    super.addHeaderView(headerView);
    upAnim = createRotateAnim(0f, -180f);
    downAnim = createRotateAnim(-180f, -360f);
  }
  private void initFooterView() {
    footerView = View.inflate(getContext(), R.layout.footer_view, null);
    footerView.measure(0, 0);// 主动触发测量,mesure内部会调用onMeasure
    footerViewHeight = footerView.getMeasuredHeight();
    hideFooterView();
    super.addFooterView(footerView);
    super.setOnScrollListener(new OnScrollListener() {
      // 当ListView滚动的状态发生改变的时候会调用这个方法
      @Override
      public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == OnScrollListener.SCROLL_STATE_IDLE  // ListView处于空闲状态
            && getLastVisiblePosition() == getCount() - 1  // 界面上可见的最后一条item是ListView中最后的一条item
            && loadingMore == false              // 如果当前没有去做正在加载更多的事情
            ) {
          loadingMore = true;
          showFooterView();
          setSelection(getCount() - 1);
          if (mOnRefreshingListener != null) {
            mOnRefreshingListener.onLoadMore();
          }
        }
      }
      // 当ListView滚动的时候会调用这个方法
      @Override
      public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      }
    });
  }
  private void hideFooterView() {
    int paddingTop = -footerViewHeight;
    setFooterViewPaddingTop(paddingTop);
  }
  private void showFooterView() {
    int paddingTop = 0;
    setFooterViewPaddingTop(paddingTop);
  }
  private void setFooterViewPaddingTop(int paddingTop) {
    footerView.setPadding(0, paddingTop, 0, 0);
  }
  /**
   * 设置显示进度的圈圈
   * @param showProgressBar 如果是true,则显示ProgressBar,否则的话显示箭头
   */
  private void showRefreshingProgressBar(boolean showProgressBar) {
    progress_bar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
    iv_arrow.setVisibility(!showProgressBar ? View.VISIBLE : View.GONE);
    if (showProgressBar) {
      iv_arrow.clearAnimation();  // 有动画的View要清除动画才能真正的隐藏
    }
  }
  /**
   * 创建旋转动画
   * @param fromDegrees 从哪个角度开始转
   * @param toDegrees 转到哪个角度
   * @return
   */
  private RotateAnimation createRotateAnim(float fromDegrees, float toDegrees) {
    int pivotXType = RotateAnimation.RELATIVE_TO_SELF;    // 旋转点的参照物
    int pivotYType = RotateAnimation.RELATIVE_TO_SELF;    // 旋转点的参照物
    float pivotXValue = 0.5f;  // 旋转点x方向的位置
    float pivotYValue = 0.5f;  // 旋转点y方向的位置
    RotateAnimation ra = new RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue);
    ra.setDuration(300);
    ra.setFillAfter(true);  // 让动画停留在结束位置
    return ra;
  }
  /** 隐藏HeaderView */
  private void hideHeaderView() {
    int paddingTop = -headerViewHeight;
    setHeaderViewPaddingTop(paddingTop);
  }
  /** 显示HeaderView */
  private void showHeaderView() {
    int paddingTop = 0;
    setHeaderViewPaddingTop(paddingTop);
  }
  /**
   * 设置HeaderView的paddingTop
   * @param paddingTop
   */
  private void setHeaderViewPaddingTop(int paddingTop) {
    headerView.setPadding(0, paddingTop, 0, 0);
  }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
    case MotionEvent.ACTION_DOWN:
      downY = ev.getY();
      break;
    case MotionEvent.ACTION_MOVE:
      if (currentState == STATE_REFRESHING) {
        // 如果当前已经是“正在刷新“的状态了,则不用去处理下拉刷新了
        return super.onTouchEvent(ev);
      }
      int fingerMoveDistanceY = (int) (ev.getY() - downY);    // 手指移动的距离
      // 如果是向下滑动,并且界面上可见的第一条item是ListView的索引为0的item时我们才处理下拉刷新的操作
      if (fingerMoveDistanceY > 0 && getFirstVisiblePosition() == 0) {
        int paddingTop = -headerViewHeight + fingerMoveDistanceY;
        setHeaderViewPaddingTop(paddingTop);
        if (paddingTop < 0 && currentState != STATE_PULL_TO_REFRESH) {
          // 如果paddingTop小于0,说明HeaderView没有完全显示出来,则进入下拉刷新的状态
          currentState = STATE_PULL_TO_REFRESH;
          tv_state.setText("下拉刷新");
          iv_arrow.startAnimation(downAnim);
          showRefreshingProgressBar(false);
          // 让箭头转一下
        } else if (paddingTop >= 0 && currentState != STATE_RELEASE_REFRESH) {
          // 如果paddingTop>=0,说明HeaderView已经完全显示出来,则进入松开刷新的状态
          currentState = STATE_RELEASE_REFRESH;
          tv_state.setText("松开刷新");
          iv_arrow.startAnimation(upAnim);
          showRefreshingProgressBar(false);
        }
        return true;
      }
      break;
    case MotionEvent.ACTION_UP:
      if (currentState == STATE_RELEASE_REFRESH) {
        // 如果当前状态是松开刷新,并且抬起了手,则进入正在刷新状态
        currentState = STATE_REFRESHING;
        tv_state.setText("正在刷新");
        showRefreshingProgressBar(true);
        showHeaderView();
        if (mOnRefreshingListener != null) {
          mOnRefreshingListener.onRefreshing();
        }
      } else if (currentState == STATE_PULL_TO_REFRESH) {
        // 如果抬起手时是下拉刷新状态,则把HeaderView完成隐藏
        hideHeaderView();
      }
      break;
    }
    return super.onTouchEvent(ev);
  }
  public void setOnRefreshingListener(OnRefreshingListener mOnRefreshingListener) {
    this.mOnRefreshingListener = mOnRefreshingListener;
  }
  /** ListView刷新的监听器 */
  public interface OnRefreshingListener {
    /** 当ListView可以刷新数据的时候会调用这个方法 */
    void onRefreshing();
    /** 当ListView可以加载更多 的时候会调用这个方法 */
    void onLoadMore();
  }
  /** 联网刷新数据的操作已经完成了 */
  public void onRefreshComplete() {
    hideHeaderView();
    currentState = STATE_PULL_TO_REFRESH;
    showRefreshingProgressBar(false);
  }
  /** 加载更多新数据的操作已经完成了 */
  public void onLoadmoreComplete() {
    hideFooterView();
    loadingMore = false;
  }
}

 方案二: listview的多种样式显示

设置listview的适配器的时候可以实现两个方法: getViewTypeCount()和getItemViewType(),前者指定条目的种类,后者返回具体的类型,这样可以根据不同的类型设计相关的样式,包括上拉加载更多,和下拉刷新,两者类似,因此这里仅仅给出加载更多的写法。具体实现如下:

1、重写getViewTypeCount()和getItemViewType(),这里包括普通的item条目和加载更多的条目,所以getViewTypeCount()返回值为2;

@Override
  public int getViewTypeCount() {
    return super.getViewTypeCount() + 1;
  }
  @Override
  public int getItemViewType(int position) {
    if (position == getCount() - 1) {
      return 0;
    } else {
      return addViewType(position); //构造一个方法出来,方便子类修改,添加更多的样式
    }
  }
  public int addViewType(int position) {
    return 1;
  }

2、在getview()中针对不同的类型添加布局:

 @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    BaseHoldle holdle;
    if (convertView == null) {
      if (getItemViewType(position) == 0) { //type为0 表示应该加载加载更多的视图
        holdle = getLoadmoreHoldle();
      } else {                //否则为普通视图
        holdle = getSpecialBaseHoldle(position);
      }
    } else {
      holdle = (BaseHoldle) convertView.getTag();
    }
    if (getItemViewType(position) == 0) {   //加载更多视图,请求网络获取数据
      if (havemore()) {
        holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_LODING);
        triggleLoadMoreData();
      } else {
        holdle.setDataAndRefreshHoldleView(LoadmoreHoldle.LOADMORE_NONE);
      }
    } else {                 //普通视图视图,请求网络获取数据
      T data = (T) mdata.get(position);
      holdle.setDataAndRefreshHoldleView(data);
    }
    mHoldleView = holdle.mHoldleView;
    mHoldleView.setScaleX(0.6f);
    mHoldleView.setScaleY(0.6f);
    ViewCompat.animate(mHoldleView).scaleX(1).scaleY(1).setDuration(400).setInterpolator(new OvershootInterpolator(4)).start();
    return mHoldleView;
  }

3、具体的加载更多视图的实现

private BaseHoldle getLoadmoreHoldle() {
    if (mLoadmoreHoldle == null) {
      mLoadmoreHoldle = new LoadmoreHoldle();
    }
    return mLoadmoreHoldle;
  }
  public class LoadmoreHoldle extends BaseHoldle {
  @Bind(R.id.item_loadmore_container_loading)
  LinearLayout itemloadmorecontainerloading;
  @Bind(R.id.item_loadmore_container_retry)
  LinearLayout itemloadmorecontainerretry;
  @Bind(R.id.item_loadmore_tv_retry)
  TextView item_loadmore_tv_retry;
  public static final int LOADMORE_LODING = 0;
  public static final int LOADMORE_ERROR = 1;
  public static final int LOADMORE_NONE = 2;
  private int mCurretState;
  @Override
  public void refreshHoldleView(Object data) {
    itemloadmorecontainerloading.setVisibility(View.GONE);
    itemloadmorecontainerretry.setVisibility(View.GONE);
    mCurretState = (int) data;
    switch (mCurretState) {
      case LOADMORE_LODING:
        itemloadmorecontainerloading.setVisibility(View.VISIBLE);
        break;
      case LOADMORE_ERROR:
        itemloadmorecontainerretry.setVisibility(View.VISIBLE);
        break;
      case LOADMORE_NONE:
        break;
    }
  }
  @Override
  public View ininViewHoldle() {
    View view = View.inflate(UiUtils.getContext(), R.layout.itemloadmore, null);
    ButterKnife.bind(this, view);
    return view;
  }
}
//holder基类,提取公共的方法
public abstract class BaseHoldle<T> {
  public View mHoldleView;
  public T mdata;
  public BaseHoldle() {
    mHoldleView = ininViewHoldle();
    mHoldleView.setTag(this);
  }
  public void setDataAndRefreshHoldleView(T mdata) {
    this.mdata = mdata;
    refreshHoldleView(mdata);
  }
  public abstract void refreshHoldleView(T data);
  public abstract View ininViewHoldle();
}

方案三: SwipeRefreshLayout实现下来刷新

SwipeRefreshLayout对下不兼容,且只有下拉刷新功能没有上拉加载更多的功能。当时作为Andriod5.0之后的新特性,使用起来方便,可以直接调用系统的API。使用方法也较为简单。具体实现如下:

首先声明控件,设置颜色:

 refreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh);
   refreshLayout.setOnRefreshListener(this);
   refreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright,
      android.R.color.holo_green_light,android.R.color.holo_orange_light,
      android.R.color.holo_red_light);
   refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);
   refreshLayout.setProgressBackgroundColor(R.color.refresh_bg);

写一个类实现SwipeRefreshLayout.OnRefreshListener,重写onRefresh()方法:

@Override
  public void onRefresh() {
   refreshLayout.postDelayed(new Runnable() {
    @Override
    public void run() {
     //请求网络,获取数据
     refreshLayout.setRefreshing(false);
    }
    },3000);
  }

以上所述是小编给大家介绍的Android中Listview下拉刷新和上拉加载更多的多种实现方案,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android中ListView下拉刷新的实现代码

    Android中ListView下拉刷新 实现效果图: ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: package net.loonggg.listview; import java.util.Date; import android.content.Context; import android.util.AttributeSet; import a

  • Android使用ListView实现下拉刷新及上拉显示更多的方法

    本文实例讲述了Android使用ListView实现下拉刷新及上拉显示更多的方法.分享给大家供大家参考,具体如下: 今天得需求是做listview+上下拉动在header和footer显示progressdialog,但不影响用户操作 直接上代码,我已经加上注释了,自己看. package com.stay.main; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap;

  • Android-自定义控件之ListView下拉刷新的实现

    自定义控件学了很久了,发现学了总是忘,于是打算用博客来记录自己学习的知识点. 今天是自定义ListView来实现下拉刷新,这些文章都是借鉴慕课网上的视频来写的. 自定义一个控件,先是看它继承于那个控件,如果我们继承View控件的话,那得让我们写很多关于ListView的功能,这些东西我自己觉得很麻烦,而且也没有那个必要因为我们可以直接继承ListView,在listView的基础上来加一些我们需要的东西. 1.向ListView加Header布局 private void initView(Co

  • Android ListView实现上拉加载下拉刷新和滑动删除功能

    最近项目需要用到可以滑动删除并且带有上拉加载下拉刷新的Listview,查阅了一些资料,大多都是在SwipeMenuListView的基础上去添加头部和底部View,来扩展上拉加载和下拉刷新的功能,不过需要手动的去绘制UI及处理一些动画效果.用起来也不是特别方便.刚好项目中用到PulltorefreshLibrary库,就尝试着扩展了一个PullToRefreshSwipeMenuListView类来实现需求.先看一下效果: 实现步骤 一.组合Pulltorefresh与SwipeMenuLis

  • Android自定义listview布局实现上拉加载下拉刷新功能

    listview实现上拉加载以及下拉刷新的方式有很多.下面是我写的一种自定义的布局,复用性也比较的强.首先就是继承的listview的自定义view.   AutoListView.Java: package com.example.mic.testdemo.view; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.Bu

  • Android自定义渐变式炫酷ListView下拉刷新动画

    本文实例为大家分享了自定义渐变式炫酷动画的ListView下拉刷新,供大家参考,具体内容如下 主要要点 listview刷新过程中主要有三个步骤当前:状态为下拉刷新,当前状态为下拉刷新,当前状态为放开刷新,当前状态为正在刷新:主要思路为三个步骤分别对应三个自定义的view:即ibuRefreshFirstStepView,ibuRefreshSecondStepView,ibuRefreshThirdStepView. 效果图 ibuRefreshFirstStepView代码,例如: priv

  • Flutter 给列表增加下拉刷新和上滑加载更多功能

    有状态组件 当 Flutter 的页面需要动态更新数据的时候,就会涉及到 UI 组件需要根据数据变化更新,此时也就意味着组件有了"状态".这就类似 React 的类组件和函数组件(只是后续 React 使用了勾子函数实现了函数组件也可以有状态).在 Flutter 中,组件也分为无状态组件(StatelessWidget)和有状态组件(StatefulWidget),一般尽量使用无状态组件.但是如果组件本身需要维护自身状态的时候,就需要使用有状态组件了.有状态组件的定义形式如下: //

  • Android仿XListView支持下拉刷新和上划加载更多的自定义RecyclerView

    首先给大家展示下效果图,感觉还不错,请继续往下阅读: 下拉刷新:        上划加载        在项目更新的过程中,遇到了一个将XListView换成recyclerView的需求,而且更换完之后大体效果不能变,但是对于下拉刷新这样的效果,谷歌给出的解决方案是把RecyclerView放在一个SwipeRefreshLayout中,但是这样其实是拉下一个小圆形控件实现的,和XListView的header效果不同.在网上找了很多的别人代码,都没有实现我想要的效果,于是自己动手写了一个.

  • Android中Listview下拉刷新和上拉加载更多的多种实现方案

    listview经常结合下来刷新和上拉加载更多使用,本文总结了三种常用到的方案分别作出说明. 方案一:添加头布局和脚布局 android系统为listview提供了addfootview和addheadview两个API.这样可以直接自定义一个View,以添加视图的形式实现下来刷新和上拉加载. 实现步骤    1.创建一个类继承ListView:class PullToRefreshListView extends ListView: 2.在构造方法中添加HeadView:addHeaderVi

  • vue移动端下拉刷新和上滑加载

    本文实例为大家分享了vue移动端下拉刷新和上滑加载的具体代码,供大家参考,具体内容如下 组件 <template> <div class="mu-load-more" @touchstart="touchStart($event)" @touchmove="touchMove($event)" @touchend="touchEnd($event)"> <div class="mu-re

  • 基于iScroll实现下拉刷新和上滑加载效果

    本文实例为大家分享了iScroll下拉刷新上滑加载展示的具体代码,供大家参考,具体内容如下 html代码: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=devi

  • Android中使用RecyclerView实现下拉刷新和上拉加载

    推荐阅读:使用RecyclerView添加Header和Footer的方法                       RecyclerView的使用之HelloWorld RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍如何为RecyclerView添加下拉刷新和上拉加载,过去在ListView当中添加下拉刷新和上拉加载是非常方便的利用addHeaderView和addFooterVie

  • Android中ListView下拉刷新的实现方法实例分析

    本文实例讲述了Android中ListView下拉刷新的实现方法.分享给大家供大家参考,具体如下: ListView中的下拉刷新是非常常见的,也是经常使用的,看到有很多同学想要,那我就整理一下,供大家参考.那我就不解释,直接上代码了. 这里需要自己重写一下ListView,重写代码如下: package net.loonggg.listview; import java.util.Date; import android.content.Context; import android.util.

  • android使用PullToRefresh实现下拉刷新和上拉加载

    PullToRefresh是一套实现非常好的下拉刷新库,它支持: 1.ListView 2.ExpandableListView 3.GridView 4.WebView 等多种常用的需要刷新的View类型,而且使用起来也十分方便. demo实例下载 下载完成,将它导入到eclipse中,作为一个library导入到你的工程中就好了. 一.废话少说,下拉刷新Go. 1.在你的布局文件中加上你想用的View就好了,比如这儿我想用一个支持下拉 刷新的ExpandableListView <com.h

  • Android RecyclerView实现下拉刷新和上拉加载

    RecyclerView已经出来很久了,许许多多的项目都开始从ListView转战RecyclerView,那么,上拉加载和下拉刷新是一件很有必要的事情. 在ListView上,我们可以通过自己添加addHeadView和addFootView去添加头布局和底部局实现自定义的上拉和下拉,或者使用一些第三方库来简单的集成,例如Android-pulltorefresh或者android-Ultra-Pull-to-Refresh,后者的自定义更强,但需要自己实现上拉加载. 而在下面我们将用两种方式

随机推荐