【1】重写listView

importjava.text.SimpleDateFormat;importjava.util.Date;importcom.example.testdddleapk.R;importandroid.content.Context;importandroid.util.AttributeSet;importandroid.util.Log;importandroid.view.MotionEvent;importandroid.view.View;importandroid.view.ViewGroup;importandroid.view.animation.Animation;importandroid.view.animation.LinearInterpolator;importandroid.view.animation.RotateAnimation;importandroid.widget.AbsListView;importandroid.widget.AbsListView.OnScrollListener;importandroid.widget.BaseAdapter;importandroid.widget.ImageView;importandroid.widget.ListAdapter;importandroid.widget.ListView;importandroid.widget.ProgressBar;importandroid.widget.TextView;publicclassRefreshListViewextendsListViewimplementsOnScrollListener{privatestaticfinalintDONE=0;privatestaticfinalintPULL_TO_REFRESH=1;privatestaticfinalintRELEASE_TO_REFRESH=2;privatestaticfinalintREFRESHING=3;privatestaticfinalfloatRATIO=3;//用来设置实际间距和上边距之间的比例privateintstate;//当前下拉刷新的状态privateintfirstVisibleIndex;//在listview中第一个可以看见的itemprivateViewheadView;privateImageViewheadArrow;privateProgressBarprogressBar;privateTextViewheadTitle;privateTextViewheadLastUpdate;privateintheadContentWidth;privateintheadContentHeight;privateAnimationanimation;privateAnimationreverseAnimation;privateOnRefreshListnerrefreshListner;//刷新监听器privatebooleanisRefreshable;privatebooleanisRecored=false;//用来记录第一次按下坐标点,在整个滑动的过程中只记录一次privatefloatstartY;privatebooleanisBack=false;//是从松开刷新状态来到的下拉刷新状态publicRefreshListView(Contextcontext,AttributeSetattrs){super(context,attrs);init(context);}privatevoidinit(Contextcontext){//listview设置滑动时缓冲背景色setCacheColorHint(0xcc000000);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加入顶部ViewaddHeaderView(headView);setOnScrollListener(this);animation=newRotateAnimation(-180,0,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);animation.setDuration(250);animation.setFillAfter(true);//设定动画结束时,停留在动画结束位置(保留动画效果)animation.setInterpolator(newLinearInterpolator());//匀速变化reverseAnimation=newRotateAnimation(0,-180,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);reverseAnimation.setDuration(200);reverseAnimation.setFillAfter(true);//设定动画结束时,停留在动画结束位置(保留动画效果)reverseAnimation.setInterpolator(newLinearInterpolator());//匀速变化//设置当前headView的状态state=DONE;//设置当前下拉刷新是否可用isRefreshable=false;}/***测量headView的宽高*/privatevoidMeasureView(Viewchild){ViewGroup.LayoutParamslp=child.getLayoutParams();if(null==lp){lp=newViewGroup.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT);}intmeasureChildWidth=ViewGroup.getChildMeasureSpec(0,0,lp.width);intmeasureChildHeight;if(lp.height>0){measureChildHeight=MeasureSpec.makeMeasureSpec(lp.height,MeasureSpec.EXACTLY);}else{measureChildHeight=MeasureSpec.makeMeasureSpec(0,MeasureSpec.UNSPECIFIED);}child.measure(measureChildWidth,measureChildHeight);}privatefloattempY=0;privatefloatdownY=0;@OverridepublicbooleanonTouchEvent(MotionEventevent){switch(event.getAction()){caseMotionEvent.ACTION_DOWN:downY=event.getY();System.out.println("downY:"+downY);if(firstVisibleIndex==0&&!isRecored){startY=event.getY();isRecored=true;}break;caseMotionEvent.ACTION_MOVE://floattempY=event.getY();tempY=event.getY();System.out.println("tempy:"+tempY);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();}//向上推了从下拉刷新的状态来到刷新完成的状态elseif((tempY-startY)<=0){state=DONE;changeHeadViewOfState();}}elseif(state==RELEASE_TO_REFRESH){//向上推了还没有完全将HEADVIEW隐藏掉(可以看到一部分)//从松开刷新的状态来到下拉刷新的状态if((tempY-startY)/RATIO<headContentHeight&&(tempY-startY)>0){state=PULL_TO_REFRESH;changeHeadViewOfState();isBack=true;}//向上推了一下子推到了最上面从松开刷新的状态来到刷新完成的状态(数据不刷新的)elseif((tempY-startY)<=0){state=DONE;changeHeadViewOfState();}}elseif(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;caseMotionEvent.ACTION_UP:if(state!=REFRESHING){if(state==PULL_TO_REFRESH){//松手state=DONE;changeHeadViewOfState();}elseif(state==RELEASE_TO_REFRESH){//松手state=REFRESHING;changeHeadViewOfState();//执行数据刷新方法onRefresh();}}isRecored=false;isBack=false;break;}returnsuper.onTouchEvent(event);}/***执行下拉刷新*/privatevoidonRefresh(){if(refreshListner!=null){refreshListner.onRefresh();}}/***HeadView的状态变化效果*/privatevoidchangeHeadViewOfState(){switch(state){casePULL_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;caseRELEASE_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;caseREFRESHING: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;caseDONE: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;}}privateintlastPos;//最后一个可见的item的位置privateintcount;//item总数,注意不是当前可见的item总数privatebooleanhasFoot=false;//是否有了FootpublicvoidonScroll(AbsListViewview,intfirstVisibleItem,intvisibleItemCount,inttotalItemCount){firstVisibleIndex=firstVisibleItem;lastPos=getLastVisiblePosition();count=totalItemCount;//因为刚进入的时候,lastPos=-1,count=0,这个时候不能让它执行onAddFoot方法if(lastPos==count-1&&!hasFoot&&lastPos!=-1&&((tempY-startY)<0)){hasFoot=true;onAddFoot();}}publicvoidonScrollStateChanged(AbsListViewview,intscrollState){if(isFootLoading)return;if(lastPos==count-1&&lastPos!=-1&&hasFoot&&footer!=null&&((tempY-downY)>0)){this.removeFooterView(footer);}if(hasFoot&&scrollState==SCROLL_STATE_IDLE&&((tempY-downY)<0)){isFootLoading=true;onFootLoading();}}/***设置下拉刷新监听*/publicvoidsetOnRefreshListner(OnRefreshListnerlistener){//设置下拉刷新可用isRefreshable=true;refreshListner=listener;}//执行底部加载publicvoidonFootLoading(){if(footLoadingListener!=null&&isFootLoading&&hasFoot&&(tempY-downY)<0){footLoadingListener.onFootLoading();}}publicvoidsetOnAddFootListener(OnAddFootListeneraddFootListener){onAddFootListener=addFootListener;}//执行添加footpublicvoidonAddFoot(){if(onAddFootListener!=null&&hasFoot)onAddFootListener.addFoot();}//是否添加Foot的监听器,如果写在OnFootLoadingListener中会有延迟,效果不好//应该是先进入添加Foot的状态,再进入FootLoading的状态publicOnAddFootListeneronAddFootListener;//是否进入从底部加载数据的状态的监听器publicOnFootLoadingListenerfootLoadingListener;//正在加载底部数据privatebooleanisFootLoading=false;publicvoidsetOnFootLoadingListener(OnFootLoadingListenerfootLoading){footLoadingListener=footLoading;}/***下拉刷新监听器*/publicinterfaceOnRefreshListner{//下拉刷新的时候,在这里执行获取数据的过程voidonRefresh();}privateViewfooter=null;publicvoidsetFooter(Viewfooter){this.footer=footer;}/***上拉刷新监听器*/publicinterfaceOnFootLoadingListener{//这里是执行后台获取数据的过程voidonFootLoading();}/***添加Foot的监听器*/publicinterfaceOnAddFootListener{//这里是用户addFootView的操作voidaddFoot();}/***底部数据加载完成,用户需要加入一个removeFootView的操作*/publicvoidonFootLoadingComplete(){hasFoot=false;isFootLoading=false;}/***上拉刷新完成时所执行的操作,更改状态,隐藏head*/publicvoidonRefreshComplete(){state=DONE;changeHeadViewOfState();headLastUpdate.setText("最后刷新时间:"+newDate().toLocaleString());}@OverridepublicvoidsetAdapter(ListAdapteradapter){headLastUpdate.setText("最后刷新时间:"+newDate().toLocaleString());super.setAdapter(adapter);}}


【2】下拉刷新头部布局文件listview_header.xml

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><FrameLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="10dip"><ImageViewandroid:id="@+id/iv_listview_header_arrow"android:layout_width="40dp"android:layout_height="40dp"android:layout_gravity="center"android:minWidth="30dip"android:src="@drawable/arrow"/><ProgressBarandroid: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><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:gravity="center_horizontal"android:orientation="vertical"><TextViewandroid:id="@+id/tv_listview_header_state"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="下拉刷新"android:textColor="#FF0000"android:textSize="18sp"/><TextViewandroid: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-1012:56:12"android:textColor="@android:color/white"android:textSize="14sp"/></LinearLayout></LinearLayout>

【3】上拉加载更多布局文件listview_footer.xml

<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><LinearLayoutandroid: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"><ProgressBarandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:indeterminateDrawable="@drawable/common_progressbar"/><TextViewandroid: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

<?xmlversion="1.0"encoding="utf-8"?><rotatexmlns:android="http://schemas.android.com/apk/res/android"android:fromDegrees="0"android:pivotX="50%"android:pivotY="50%"android:toDegrees="360"><shapeandroid:innerRadiusRatio="3"android:shape="ring"android:useLevel="false"><gradientandroid:centerColor="#FF6666"android:endColor="#FF0000"android:startColor="#FFFFFF"android:type="sweep"/></shape></rotate>

【5】使用方法

adapter=newmyListAdapter(items,xxx.this);listView.setAdapter(adapter);/***下拉刷新回调*/listView.setOnRefreshListner(newOnRefreshListner(){publicvoidonRefresh(){newAsyncTask<Void,Void,ArrayList<String>>(){@OverrideprotectedArrayList<String>doInBackground(Void...params){try{//模拟从服务器获取数据的过程Thread.sleep(1500);}catch(InterruptedExceptione){e.printStackTrace();}returnnull;}//更新UI的方法,系统自动实现@OverrideprotectedvoidonPostExecute(ArrayList<String>result){data.addAll(0,result);//注意是往前添加数据adapter.notifyDataSetChanged();listView.onRefreshComplete();//完成下拉刷新,这个方法要调用super.onPostExecute(result);}}.execute();}});//上拉加载更多功能finalViewfooter=View.inflate(getActivity(),R.layout.listview_footer,null);listView.setOnAddFootListener(newOnAddFootListener(){publicvoidaddFoot(){listView.setFooter(footer);listView.addFooterView(footer);}});listView.setOnFootLoadingListener(newOnFootLoadingListener(){publicvoidonFootLoading(){newAsyncTask<Void,Void,ArrayList<String>>(){@OverrideprotectedArrayList<String>doInBackground(Void...params){try{//模拟从服务器获取数据的过程Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}returnnull;}//在doInBackground后面执行protectedvoidonPostExecute(ArrayList<String>result){data.addAll(result);//这个是往后添加数据adapter.notifyDataSetChanged();listView.onFootLoadingComplete();//完成上拉刷新,就是底部加载完毕,这个方法要调用//移除footer,这个动作不能少listView.removeFooterView(footer);super.onPostExecute(result);}}.execute();}});

【6】注意事项

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

}