android 安卓 listview 支持下拉刷新 上拉加载更多

犀渠玉剑良家子,白马金羁侠少年。这篇文章主要讲述android 安卓 listview 支持下拉刷新 上拉加载更多相关的知识,希望能为你提供帮助。
【1】重写listView

import  java.text.SimpleDateFormat; import  java.util.Date; import  android.content.Context; import  android.util.AttributeSet; import  android.util.Log; import  android.view.MotionEvent; import  android.view.View; import  android.view.ViewGroup; import  android.view.animation.Animation; import  android.view.animation.LinearInterpolator; import  android.view.animation.RotateAnimation; import  android.widget.AbsListView; import  android.widget.AbsListView.OnScrollListener; import  android.widget.BaseAdapter; import  android.widget.ImageView; import  android.widget.ListAdapter; import  android.widget.ListView; import  android.widget.ProgressBar; import  android.widget.TextView; public  class  RefreshListView  extends  ListView  implements  OnScrollListener  {    private  static  final  int  DONE  =  0;     private  static  final  int  PULL_TO_REFRESH  =  1;     private  static  final  int  RELEASE_TO_REFRESH  =  2;     private  static  final  int  REFRESHING  =  3;     private  static  final  float  RATIO  =  3; //  用来设置实际间距和上边距之间的比例    private  int  state; //  当前下拉刷新的状态    private  int  firstVisibleIndex; //  在listview中第一个可以看见的item    private  View  headView;     private  ImageView  headArrow;     private  ProgressBar  progressBar;     private  TextView  headTitle;     private  TextView  headLastUpdate;     private  int  headContentWidth;     private  int  headContentHeight;     private  Animation  animation;     private  Animation  reverseAnimation;     private  OnRefreshListner  refreshListner; //  刷新监听器    private  boolean  isRefreshable;     private  boolean  isRecored  =  false; //  用来记录第一次按下坐标点,在整个滑动的过程中  只记录一次    private  float  startY;     private  boolean  isBack  =  false; //  是从  松开刷新状态  来到的  下拉刷新状态    public  RefreshListView(Context  context,  AttributeSet  attrs)  {    super(context,  attrs);     init(context);     }    private  void  init(Context  context)  {    //  listview  设置滑动时缓冲背景色    setCacheColorHint(0x00000000);     headView  =  View.inflate(context,  R.layout.listview_header,  null);     headArrow  =  (ImageView)  headView.findViewById(R.id.iv_listview_header_arrow);     progressBar  =  (ProgressBar)  headView.findViewById(R.id.pb_listview_header);     headTitle  =  (TextView)  headView.findViewById(R.id.tv_listview_header_last_update_time);     headLastUpdate  =  (TextView)  headView  .findViewById(R.id.tv_listview_header_state);     headArrow.setMinimumWidth(50);     headArrow.setMinimumHeight(70);     MeasureView(headView);     headContentWidth  =  headView.getMeasuredWidth();     headContentHeight  =  headView.getMeasuredHeight();     headView.setPadding(0,  -1*headContentHeight,  0,  0);     //  为listView加入顶部View    addHeaderView(headView);     setOnScrollListener(this);     animation  =  new  RotateAnimation(-180,  0,  Animation.RELATIVE_TO_SELF,0.5f,  Animation.RELATIVE_TO_SELF,  0.5f);     animation.setDuration(250);     animation.setFillAfter(true); //  设定动画结束时,停留在动画结束位置  (保留动画效果)    animation.setInterpolator(new  LinearInterpolator()); //  匀速变化    reverseAnimation  =  new  RotateAnimation(0,  -180,Animation.RELATIVE_TO_SELF,  0.5f,  Animation.RELATIVE_TO_SELF,0.5f);     reverseAnimation.setDuration(200);     reverseAnimation.setFillAfter(true); //  设定动画结束时,停留在动画结束位置  (保留动画效果)    reverseAnimation.setInterpolator(new  LinearInterpolator()); //  匀速变化    //  设置当前headView的状态    state  =  DONE;     //  设置当前下拉刷新是否可用    isRefreshable  =  false;     }    /**    *  测量headView的  宽高    */    private  void  MeasureView(View  child)  {    ViewGroup.LayoutParams  lp  =  child.getLayoutParams();     if  (null  ==  lp)  {    lp  =  new  ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,  LayoutParams.WRAP_CONTENT);     }    int  measureChildWidth  =  ViewGroup.getChildMeasureSpec(0,  0,  lp.width);     int  measureChildHeight;     if  (lp.height  >   0)  {    measureChildHeight  =  MeasureSpec.makeMeasureSpec(lp.height,  MeasureSpec.EXACTLY);     }  else  {    measureChildHeight  =  MeasureSpec.makeMeasureSpec(0,  MeasureSpec.UNSPECIFIED);     }    child.measure(measureChildWidth,  measureChildHeight);     }    @Override    public  boolean  onTouchEvent(MotionEvent  event)  {    switch  (event.getAction())  {    case  MotionEvent.ACTION_DOWN:    if  (firstVisibleIndex  ==  0  & &   !isRecored)  {    startY  =  event.getY();     isRecored  =  true;     }    break;     case  MotionEvent.ACTION_MOVE:    float  tempY  =  event.getY();     if  (firstVisibleIndex  ==  0  & &   !isRecored)  {    startY  =  tempY;     isRecored  =  true;     }    if  (state  !=  REFRESHING)  {    if  (state  ==  PULL_TO_REFRESH)  {    //  向下拉了  从下拉刷新的状态  来到  松开刷新的状态    if  ((tempY  -  startY)  /  RATIO  > =  headContentHeight    & &   (tempY  -  startY)  >   0)  {    state  =  RELEASE_TO_REFRESH;     changeHeadViewOfState();     }    //  向上推了  从下拉刷新的状态  来到  刷新完成的状态    else  if  ((tempY  -  startY)  < =  0)  {    state  =  DONE;     changeHeadViewOfState();     }    }  else  if  (state  ==  RELEASE_TO_REFRESH)  {    //  向上推了  还没有完全将HEADVIEW  隐藏掉(可以看到一部分)    //  从松开刷新的状态  来到  下拉刷新的状态    if  ((tempY  -  startY)  /  RATIO  <   headContentHeight    & &   (tempY  -  startY)  >   0)  {    state  =  PULL_TO_REFRESH;     changeHeadViewOfState();     isBack  =  true;     }    //  向上推了  一下子推到了最上面  从松开刷新的状态  来到  刷新完成的状态  (数据不刷新的)    else  if  ((tempY  -  startY)  < =  0)  {    state  =  DONE;     changeHeadViewOfState();     }    }  else  if  (state  ==  DONE)  {    //  刷新完成的状态  来到  下拉刷新的状态    if  ((tempY  -  startY)  >   0)  {    state  =  PULL_TO_REFRESH;     changeHeadViewOfState();     }    }    if  (state  ==  PULL_TO_REFRESH)  {    headView.setPadding(0,(int)  ((tempY  -  startY)  /  RATIO  -  headContentHeight),0,  0);     }    if  (state  ==  RELEASE_TO_REFRESH)  {    headView.setPadding(0,  (int)  ((tempY  -  startY)  /  RATIO  -  headContentHeight),0,  0);     }    }    break;     case  MotionEvent.ACTION_UP:    if  (state  !=  REFRESHING)  {    if  (state  ==  PULL_TO_REFRESH)  {    //  松手    state  =  DONE;     changeHeadViewOfState();     }    else  if  (state  ==  RELEASE_TO_REFRESH)  {    //  松手    state  =  REFRESHING;     changeHeadViewOfState();     //  执行数据刷新方法    onRefresh();     }    }    isRecored  =  false;     isBack  =  false;     break;     }    return  super.onTouchEvent(event);     }    /**    *  执行下拉刷新    */    private  void  onRefresh()  {    if  (refreshListner  !=  null)  {    refreshListner.onRefresh();     }    }    /**    *  HeadView的状态变化效果    */    private  void  changeHeadViewOfState()  {    switch  (state)  {    case  PULL_TO_REFRESH:    headArrow.setVisibility(View.VISIBLE);     progressBar.setVisibility(View.GONE);     headTitle.setVisibility(View.VISIBLE);     headLastUpdate.setVisibility(View.VISIBLE);     headArrow.clearAnimation();     headTitle.setText("下拉可以刷新");     //由  松开刷新    到    下拉刷新    if(isBack){    headArrow.startAnimation(animation);     isBack  =  false;     }    break;     case  RELEASE_TO_REFRESH:    headArrow.setVisibility(View.VISIBLE);     progressBar.setVisibility(View.GONE);     headTitle.setVisibility(View.VISIBLE);     headLastUpdate.setVisibility(View.VISIBLE);     headArrow.clearAnimation();     headArrow.startAnimation(reverseAnimation);     headTitle.setText("松开可以刷新");     break;     case  REFRESHING:    headArrow.setVisibility(View.GONE);     progressBar.setVisibility(View.VISIBLE);     headTitle.setVisibility(View.VISIBLE);     headLastUpdate.setVisibility(View.VISIBLE);     headArrow.clearAnimation();     headTitle.setText("正在刷新...");     headView.setPadding(0,  0,  0,  0);     break;     case  DONE:    headArrow.setVisibility(View.VISIBLE);     progressBar.setVisibility(View.GONE);     headTitle.setVisibility(View.VISIBLE);     headLastUpdate.setVisibility(View.VISIBLE);     headArrow.clearAnimation();     headTitle.setText("下拉可以刷新");     headView.setPadding(0,  -1  *  headContentHeight,  0,  0);     break;     }    }    private  int  lastPos; //最后一个可见的item的位置    private  int  count; //item总数,注意不是当前可见的item总数    private  boolean  hasFoot  =  false; //是否有了Foot    public  void  onScroll(AbsListView  view,  int  firstVisibleItem,int  visibleItemCount,  int  totalItemCount)  { firstVisibleIndex  =  firstVisibleItem;     lastPos  =  getLastVisiblePosition();     count  =  totalItemCount;     //因为刚进入的时候,lastPos=-1,count=0,这个时候不能让它执行onAddFoot方法    if(lastPos==count-1  & &   !hasFoot  & &   lastPos  !=  -1){    hasFoot  =  true;     onAddFoot();     }    } public  void  onScrollStateChanged(AbsListView  view,  int  scrollState)  { if(isFootLoading)  return;     if(hasFoot  & &   scrollState==SCROLL_STATE_IDLE){    isFootLoading  =  true;     onFootLoading();     }  } /**    *  设置下拉刷新监听    */    public  void  setOnRefreshListner(OnRefreshListner  listener)  {    //  设置下拉刷新可用    isRefreshable  =  true;     refreshListner  =  listener;     }    //执行底部加载    public  void  onFootLoading(){    if(footLoadingListener!=null  & &   isFootLoading)    footLoadingListener.onFootLoading();     }    public  void  setOnAddFootListener(OnAddFootListener  addFootListener){    onAddFootListener  =  addFootListener;     }    //执行添加foot    public  void  onAddFoot(){    if(onAddFootListener!=null  & &   hasFoot)    onAddFootListener.addFoot();     }    //是否添加Foot的监听器,如果写在OnFootLoadingListener中会有延迟,效果不好    //应该是先进入添加Foot的状态,再进入FootLoading的状态    public  OnAddFootListener  onAddFootListener;     //是否进入从底部加载数据的状态的监听器    public  OnFootLoadingListener  footLoadingListener;     //正在加载底部数据    private  boolean  isFootLoading  =  false;     public  void  setOnFootLoadingListener(OnFootLoadingListener  footLoading){    footLoadingListener  =  footLoading;     }    /**    *  下拉刷新监听器    */    public  interface  OnRefreshListner  {    //  下拉刷新的时候,在这里执行获取数据的过程  void  onRefresh();     }    /**    *  上拉刷新监听器    */    public  interface  OnFootLoadingListener{    //  这里是执行后台获取数据的过程  void  onFootLoading();     }    /**    *  添加Foot的监听器    */    public  interface  OnAddFootListener{    //  这里是用户addFootView的操作  void  addFoot();     }    /**    *  底部数据加载完成,用户需要加入一个removeFootView的操作    */    public  void  onFootLoadingComplete(){    hasFoot  =  false;     isFootLoading  =  false;     }    /**    *  上拉刷新完成时  所执行的操作,更改状态,隐藏head    */    public  void  onRefreshComplete()  {    state  =  DONE;     changeHeadViewOfState();     headLastUpdate.setText("最后刷新时间:  "  +  new  Date().toLocaleString());     }    @Override public  void  setAdapter(ListAdapter  adapter)  { headLastUpdate.setText("最后刷新时间:  "  +  new  Date().toLocaleString());     super.setAdapter(adapter);     } }



【2】下拉刷新头部布局文件listview_header.xml
< ?xml  version="1.0"  encoding="utf-8"?> < LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"  > < FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dip"  > < ImageView android:id="@+id/iv_listview_header_arrow" android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="center" android:minWidth="30dip" android:src="https://www.songbingjia.com/android/@drawable/arrow"  /> < ProgressBar android:id="@+id/pb_listview_header" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:indeterminateDrawable="@drawable/common_progressbar" android:visibility="gone"  /> < /FrameLayout> < LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:orientation="vertical"  > < TextView android:id="@+id/tv_listview_header_state" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下拉刷新" android:textColor="#FF0000" android:textSize="18sp"  /> < TextView android:id="@+id/tv_listview_header_last_update_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dip" android:text="最后刷新时间:  2014-10-10  12:56:12" android:textColor="@android:color/white" android:textSize="14sp"  /> < /LinearLayout> < /LinearLayout>

【3】上拉加载更多布局文件listview_footer.xml
< ?xml  version="1.0"  encoding="utf-8"?> < LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"  > < LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margin="10dip" android:gravity="center_vertical" android:orientation="horizontal"  > < ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:indeterminateDrawable="@drawable/common_progressbar"  /> < TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dip" android:text="加载更多..." android:textColor="#FF0000" android:textSize="18sp"  /> < /LinearLayout> < /LinearLayout>

【4】progressBar--common_progressbar.xml
< ?xml  version="1.0"  encoding="utf-8"?> < rotate  xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="360"  > < shape android:innerRadiusRatio="3" android:shape="ring" android:useLevel="false"  > < gradient android:centerColor="#FF6666" android:endColor="#FF0000" android:startColor="#FFFFFF" android:type="sweep"  /> < /shape> < /rotate>

【5】使用方法
adapter=new  myListAdapter(items,xxx.this); listView.setAdapter(adapter); /** *  下拉刷新回调 */ listView.setOnRefreshListner(new  OnRefreshListner()  {         public  void  onRefresh()  {                 new  AsyncTask< Void,  Void,  ArrayList< String> > (){    @Override    protected  ArrayList< String>   doInBackground(Void...  params)  {                            try  {            //模拟从服务器获取数据的过程    Thread.sleep(1500);     }  catch  (InterruptedException  e)  {            e.printStackTrace();     }                            return  null;     }    //更新UI的方法,系统自动实现    @Override    protected  void  onPostExecute(ArrayList< String>   result)  {            data.addAll(0,result); //注意是往前添加数据            adapter.notifyDataSetChanged();             listView.onRefreshComplete(); //完成下拉刷新,这个方法要调用         super.onPostExecute(result);     }    }.execute();             } }); //上拉加载更多功能 final  View  footer  =  View.inflate(getActivity(),  R.layout.listview_footer,  null);                   listView.setOnAddFootListener(new  OnAddFootListener()  {         public  void  addFoot()  { listView.addFooterView(footer);             } }); listView.setOnFootLoadingListener(new  OnFootLoadingListener()  {                            public  void  onFootLoading()  {    new  AsyncTask< Void,  Void,  ArrayList< String> > (){            @Override            protected  ArrayList< String>   doInBackground(Void...  params)  {                    try  {                              //模拟从服务器获取数据的过程                              Thread.sleep(2000);                               }  catch  (InterruptedException  e)  {                                      e.printStackTrace();                                   }                              return  null;               }      //在doInBackground后面执行            protected  void  onPostExecute(ArrayList< String>   result)  {                      data.addAll(result); //这个是往后添加数据                  adapter.notifyDataSetChanged();                   listView.onFootLoadingComplete(); //完成上拉刷新,就是底部加载完毕,这个方法要调用                  //移除footer,这个动作不能少                  listView.removeFooterView(footer);                   super.onPostExecute(result);             }    }.execute();             }    });

【6】注意事项
  listview设置项目点击事件
【android 安卓 listview 支持下拉刷新 上拉加载更多】listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView< ?> parent, View view,int position, long id) {
if(position==0||position==items.length()+1) return;
        //获取每项的数据,position需减1,第0项为listview_head 
}



    推荐阅读