GridView基于pulltorefresh实现下拉刷新 上拉加载更多功能(推荐)
原理和listview一样,都是重写Android原生控件
Activity
packagecom.example.refreshgridview;
importjava.util.ArrayList;
importjava.util.List;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.widget.GridView;
importandroid.widget.Toast;
importcom.example.refreshgridview.PullToRefreshBase.OnRefreshListener;
publicclassMainActivityextendsActivity{
privatePullToRefreshGridViewmPullRefreshGridView;
privateGridViewmGridView;
privateGridViewAdapteradapter;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPullRefreshGridView=(PullToRefreshGridView)findViewById(R.id.video_gridView);
mPullRefreshGridView.init(PullToRefreshGridView.MODE_BOTH);
mGridView=mPullRefreshGridView.getRefreshableView();
mPullRefreshGridView.setOnRefreshListener(refreshListener);
List<String>list=newArrayList<String>();
for(inti=0;i<40;i++){
list.add(i+"");
}
adapter=newGridViewAdapter(MainActivity.this,list);
mGridView.setAdapter(adapter);
}
privateOnRefreshListenerrefreshListener=newOnRefreshListener(){
@Override
publicvoidonRefresh(intmode){
if(PullToRefreshGridView.MODE_PULL_DOWN_TO_REFRESH==mPullRefreshGridView.getCurrentMode()){
Toast.makeText(MainActivity.this,"下拉刷新",Toast.LENGTH_SHORT).show();
mPullRefreshGridView.onRefreshComplete();
}elseif(mode==PullToRefreshGridView.MODE_PULL_UP_TO_REFRESH){
//加载更多
Toast.makeText(MainActivity.this,"上拉加载更多",Toast.LENGTH_SHORT).show();
mPullRefreshGridView.onRefreshComplete();
}
}
};
}
adapter
packagecom.example.refreshgridview;
importjava.util.ArrayList;
importjava.util.List;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.text.TextUtils;
importandroid.view.LayoutInflater;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.widget.BaseAdapter;
importandroid.widget.TextView;
publicclassGridViewAdapterextendsBaseAdapter{
privateList<String>mList=newArrayList<String>();
privateContextmContext;
publicGridViewAdapter(Contextcontext,List<String>list){
super();
this.mContext=context;
this.mList=list;
}
@Override
publicintgetCount(){
returnmList.size();
}
@Override
publicStringgetItem(intposition){
returnmList.get(position);
}
@Override
publiclonggetItemId(intposition){
returnposition;
}
@Override
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
ChildHolderOneholder;
if(convertView==null){
convertView=LayoutInflater.from(mContext).inflate(R.layout.item_grid_live_show,parent,false);
holder=newChildHolderOne();
holder.tvTitle=(TextView)convertView.findViewById(R.id.title_tv);
convertView.setTag(holder);
}else{
holder=(ChildHolderOne)convertView.getTag();
}
returnconvertView;
}
classChildHolderOne{
TextViewtvTitle;
}
}
PullToRefreshGridView
packagecom.example.refreshgridview;
importandroid.content.Context;
importandroid.util.AttributeSet;
importandroid.view.ContextMenu.ContextMenuInfo;
importandroid.view.View;
importandroid.widget.GridView;
publicclassPullToRefreshGridViewextendsPullToRefreshAdapterViewBase<GridView>{
classInternalGridViewextendsGridViewimplementsEmptyViewMethodAccessor{
publicInternalGridView(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
@Override
publicvoidsetEmptyView(ViewemptyView){
PullToRefreshGridView.this.setEmptyView(emptyView);
}
@Override
publicvoidsetEmptyViewInternal(ViewemptyView){
super.setEmptyView(emptyView);
}
@Override
publicContextMenuInfogetContextMenuInfo(){
returnsuper.getContextMenuInfo();
}
}
publicPullToRefreshGridView(Contextcontext){
super(context);
}
publicPullToRefreshGridView(Contextcontext,intmode){
super(context,mode);
}
publicPullToRefreshGridView(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
@Override
protectedfinalGridViewcreateRefreshableView(Contextcontext,AttributeSetattrs){
GridViewgv=newInternalGridView(context,attrs);
//UseGeneratedID(fromres/values/ids.xml)
gv.setId(R.id.gridview);
returngv;
}
@Override
publicContextMenuInfogetContextMenuInfo(){
return((InternalGridView)getRefreshableView()).getContextMenuInfo();
}
}
PullToRefreshBase
packagecom.example.refreshgridview;
importandroid.content.Context;
importandroid.os.Handler;
importandroid.util.AttributeSet;
importandroid.view.MotionEvent;
importandroid.view.View;
importandroid.view.ViewConfiguration;
importandroid.view.ViewGroup;
importandroid.view.animation.AccelerateDecelerateInterpolator;
importandroid.view.animation.Interpolator;
importandroid.widget.LinearLayout;
importandroid.widget.TextView;
/**
*
*@authorzlw
*/
publicabstractclassPullToRefreshBase<TextendsView>extendsLinearLayout{
finalclassSmoothScrollRunnableimplementsRunnable{
staticfinalintANIMATION_DURATION_MS=190;
staticfinalintANIMATION_FPS=1000/60;
privatefinalInterpolatorinterpolator;
privatefinalintscrollToY;
privatefinalintscrollFromY;
privatefinalHandlerhandler;
privatebooleancontinueRunning=true;
privatelongstartTime=-1;
privateintcurrentY=-1;
publicSmoothScrollRunnable(Handlerhandler,intfromY,inttoY){
this.handler=handler;
this.scrollFromY=fromY;
this.scrollToY=toY;
this.interpolator=newAccelerateDecelerateInterpolator();
}
@Override
publicvoidrun(){
/**
*OnlysetstartTimeifthisisthefirsttimewe'restarting,else
*actuallycalculatetheYdelta
*/
if(startTime==-1){
startTime=System.currentTimeMillis();
}else{
/**
*Wedodoallcalculationsinlongtoreducesoftwarefloat
*calculations.Weuse1000asitgivesusgoodaccuracyand
*smallroundingerrors
*/
longnormalizedTime=(1000*(System.currentTimeMillis()-startTime))
/ANIMATION_DURATION_MS;
normalizedTime=Math.max(Math.min(normalizedTime,1000),0);
finalintdeltaY=Math
.round((scrollFromY-scrollToY)
*interpolator
.getInterpolation(normalizedTime/1000f));
this.currentY=scrollFromY-deltaY;
setHeaderScroll(currentY);
}
//Ifwe'renotatthetargetY,keepgoing...
if(continueRunning&&scrollToY!=currentY){
handler.postDelayed(this,ANIMATION_FPS);
}
}
publicvoidstop(){
this.continueRunning=false;
this.handler.removeCallbacks(this);
}
};
//===========================================================
//Constants
//===========================================================
staticfinalfloatFRICTION=2.0f;
staticfinalintPULL_TO_REFRESH=0x0;
staticfinalintRELEASE_TO_REFRESH=0x1;
staticfinalintREFRESHING=0x2;
staticfinalintMANUAL_REFRESHING=0x3;
publicstaticfinalintMODE_PULL_DOWN_TO_REFRESH=0x1;
publicstaticfinalintMODE_PULL_UP_TO_REFRESH=0x2;
publicstaticfinalintMODE_BOTH=0x3;
//===========================================================
//Fields
//===========================================================
privateinttouchSlop;
privatefloatinitialMotionY;
privatefloatlastMotionX;
privatefloatlastMotionY;
privatebooleanisBeingDragged=false;
privateintstate=PULL_TO_REFRESH;
privateintmode=MODE_PULL_UP_TO_REFRESH;
privateintcurrentMode;
privatebooleandisableScrollingWhileRefreshing=true;
TrefreshableView;
privatebooleanisPullToRefreshEnabled=true;
privateLoadingLayoutheaderLayout;
privateLoadingLayoutfooterLayout;
privateintheaderHeight;
privatefinalHandlerhandler=newHandler();
privateOnRefreshListeneronRefreshListener;
privateSmoothScrollRunnablecurrentSmoothScrollRunnable;
//===========================================================
//Constructors
//===========================================================
publicPullToRefreshBase(Contextcontext){
super(context);
init(context,null);
}
publicPullToRefreshBase(Contextcontext,intmode){
super(context);
this.mode=mode;
init(context,null);
}
publicPullToRefreshBase(Contextcontext,AttributeSetattrs){
super(context,attrs);
init(context,attrs);
}
//===========================================================
//Getter&Setter
//===========================================================
/**
*Deprecated.Use{@link#getRefreshableView()}fromnowon.
*
*@deprecated
*@returnTheRefreshableViewwhichiscurrentlywrapped
*/
publicfinalTgetAdapterView(){
returnrefreshableView;
}
/**
*GettheWrappedRefreshableView.Anythingreturnedherehasalreadybeen
*addedtothecontentview.
*
*@returnTheViewwhichiscurrentlywrapped
*/
publicfinalTgetRefreshableView(){
returnrefreshableView;
}
/**
*WhetherPull-to-Refreshisenabled
*
*@returnenabled
*/
publicfinalbooleanisPullToRefreshEnabled(){
returnisPullToRefreshEnabled;
}
/**
*ReturnswhetherthewidgethasdisabledscrollingontheRefreshableView
*whilerefreshing.
*
*@returntrueifthewidgethasdisabledscrollingwhilerefreshing
*/
publicfinalbooleanisDisableScrollingWhileRefreshing(){
returndisableScrollingWhileRefreshing;
}
/**
*ReturnswhethertheWidgetiscurrentlyintheRefreshingstate
*
*@returntrueiftheWidgetiscurrentlyrefreshing
*/
publicfinalbooleanisRefreshing(){
returnstate==REFRESHING||state==MANUAL_REFRESHING;
}
/**
*BydefaulttheWidgetdisabledscrollingontheRefreshableViewwhile
*refreshing.Thismethodcanchangethisbehaviour.
*
*@paramdisableScrollingWhileRefreshing
*-trueifyouwanttodisablescrollingwhilerefreshing
*/
publicfinalvoidsetDisableScrollingWhileRefreshing(
booleandisableScrollingWhileRefreshing){
this.disableScrollingWhileRefreshing=disableScrollingWhileRefreshing;
}
/**
*MarkthecurrentRefreshascomplete.WillResettheUIandhidethe
*RefreshingView
*/
publicfinalvoidonRefreshComplete(){
if(state!=PULL_TO_REFRESH){
resetHeader();
if(onShowLayoutListener!=null){
onShowLayoutListener.onDismiss();
}
}
}
/**
*SetOnRefreshListenerfortheWidget
*
*@paramlistener
*-ListenertobeusedwhentheWidgetissettoRefresh
*/
publicfinalvoidsetOnRefreshListener(OnRefreshListenerlistener){
onRefreshListener=listener;
}
/**
*autoloadheaderLayouttorefresh
*
*@paramlistener
*/
publicfinalvoidsetFirstAutoPullUpToRefresh(OnRefreshListenerlistener){
setRefreshingInternal(true,MODE_PULL_DOWN_TO_REFRESH);
listener.onRefresh(MODE_PULL_DOWN_TO_REFRESH);
}
/**
*setrefreshLable,defaultusenull
*
*@parampullLabel
*@paramreleaseLabel
*@paramrefreshingLabel
*/
publicvoidsetRefreshLabel(StringpullLabel,StringreleaseLabel,
StringrefreshingLabel){
if(pullLabel!=null){
setPullLabel(pullLabel);
}
if(releaseLabel!=null){
setReleaseLabel(releaseLabel);
}
if(refreshingLabel!=null){
setRefreshingLabel(refreshingLabel);
}
}
/**
*Amutatortoenable/disablePull-to-RefreshforthecurrentView
*
*@paramenable
*WhetherPull-To-Refreshshouldbeused
*/
publicfinalvoidsetPullToRefreshEnabled(booleanenable){
this.isPullToRefreshEnabled=enable;
}
/**
*SetTexttoshowwhentheWidgetisbeingpulled,andwillrefreshwhen
*released
*
*@paramreleaseLabel
*-Stringtodisplay
*/
privatevoidsetReleaseLabel(StringreleaseLabel){
if(null!=headerLayout){
headerLayout.setReleaseLabel(releaseLabel);
}
if(null!=footerLayout){
footerLayout.setReleaseLabel(releaseLabel);
}
}
/**
*SetTexttoshowwhentheWidgetisbeingPulled
*
*@parampullLabel
*-Stringtodisplay
*/
privatevoidsetPullLabel(StringpullLabel){
if(null!=headerLayout){
headerLayout.setPullLabel(pullLabel);
}
if(null!=footerLayout){
footerLayout.setPullLabel(pullLabel);
}
}
/**
*SetTexttoshowwhentheWidgetisrefreshing
*
*@paramrefreshingLabel
*-Stringtodisplay
*/
privatevoidsetRefreshingLabel(StringrefreshingLabel){
if(null!=headerLayout){
headerLayout.setRefreshingLabel(refreshingLabel);
}
if(null!=footerLayout){
footerLayout.setRefreshingLabel(refreshingLabel);
}
}
publicfinalvoidsetRefreshing(){
this.setRefreshing(true);
}
/**
*SetstheWidgettobeintherefreshstate.TheUIwillbeupdatedto
*showthe'Refreshing'view.
*
*@paramdoScroll
*-trueifyouwanttoforceascrolltotheRefreshingview.
*/
publicfinalvoidsetRefreshing(booleandoScroll){
if(!isRefreshing()){
setRefreshingInternal(doScroll);
state=MANUAL_REFRESHING;
}
}
publicfinalbooleanhasPullFromTop(){
returncurrentMode!=MODE_PULL_UP_TO_REFRESH;
}
//===========================================================
//Methodsfor/fromSuperClass/Interfaces
//===========================================================
@Override
publicfinalbooleanonTouchEvent(MotionEventevent){
if(!isPullToRefreshEnabled){
returnfalse;
}
if(isRefreshing()&&disableScrollingWhileRefreshing){
returntrue;
}
if(event.getAction()==MotionEvent.ACTION_DOWN
&&event.getEdgeFlags()!=0){
returnfalse;
}
switch(event.getAction()){
caseMotionEvent.ACTION_MOVE:{
if(isBeingDragged){
if(Math.abs(event.getY()-downLocation)>5
&&onShowLayoutListener!=null){
onShowLayoutListener.onShow();
}
lastMotionY=event.getY();
this.pullEvent();
returntrue;
}
break;
}
caseMotionEvent.ACTION_DOWN:{
if(isReadyForPull()){
downLocation=event.getY();
lastMotionY=initialMotionY=event.getY();
returntrue;
}
break;
}
caseMotionEvent.ACTION_CANCEL:
caseMotionEvent.ACTION_UP:{
if(isBeingDragged){
isBeingDragged=false;
if(state==RELEASE_TO_REFRESH&&null!=onRefreshListener){
setRefreshingInternal(true);
onRefreshListener.onRefresh(currentMode);
}else{
smoothScrollTo(0);
if(onShowLayoutListener!=null){
onShowLayoutListener.onDismiss();
}
}
returntrue;
}
break;
}
}
returnfalse;
}
//remebertodownlocation
privatefloatdownLocation=0;
@Override
publicfinalbooleanonInterceptTouchEvent(MotionEventevent){
if(!isPullToRefreshEnabled){
returnfalse;
}
if(isRefreshing()&&disableScrollingWhileRefreshing){
returntrue;
}
finalintaction=event.getAction();
if(action==MotionEvent.ACTION_CANCEL
||action==MotionEvent.ACTION_UP){
isBeingDragged=false;
returnfalse;
}
if(action!=MotionEvent.ACTION_DOWN&&isBeingDragged){
returntrue;
}
switch(action){
caseMotionEvent.ACTION_MOVE:{
if(isReadyForPull()){
finalfloaty=event.getY();
finalfloatdy=y-lastMotionY;
finalfloatyDiff=Math.abs(dy);
finalfloatxDiff=Math.abs(event.getX()-lastMotionX);
if(yDiff>touchSlop&&yDiff>xDiff){
if((mode==MODE_PULL_DOWN_TO_REFRESH||mode==MODE_BOTH)
&&dy>=0.0001f&&isReadyForPullDown()){
lastMotionY=y;
isBeingDragged=true;
if(mode==MODE_BOTH){
currentMode=MODE_PULL_DOWN_TO_REFRESH;
}
}elseif((mode==MODE_PULL_UP_TO_REFRESH||mode==MODE_BOTH)
&&dy<=0.0001f&&isReadyForPullUp()){
lastMotionY=y;
isBeingDragged=true;
if(mode==MODE_BOTH){
currentMode=MODE_PULL_UP_TO_REFRESH;
}
}
}
}
break;
}
caseMotionEvent.ACTION_DOWN:{
if(isReadyForPull()){
lastMotionY=initialMotionY=event.getY();
lastMotionX=event.getX();
isBeingDragged=false;
}
break;
}
caseMotionEvent.ACTION_UP:
break;
}
setRefreshLabel(currentMode);
returnisBeingDragged;
}
protectedvoidaddRefreshableView(Contextcontext,TrefreshableView){
addView(refreshableView,newLinearLayout.LayoutParams(
LayoutParams.FILL_PARENT,0,1.0f));
}
/**
*ThisisimplementedbyderivedclassestoreturnthecreatedView.Ifyou
*needtouseacustomView(suchasacustomListView),overridethis
*methodandreturnaninstanceofyourcustomclass.
*
*BesuretosettheIDoftheviewinthismethod,especiallyifyou're
*usingaListActivityorListFragment.
*
*@paramcontext
*@paramattrs
*AttributeSetfromwrappedclass.Meansthatanythingyou
*includeintheXMLlayoutdeclarationwillberoutedtothe
*createdView
*@returnNewinstanceoftheRefreshableView
*/
protectedabstractTcreateRefreshableView(Contextcontext,
AttributeSetattrs);
publicfinalintgetCurrentMode(){
returncurrentMode;
}
protectedfinalLoadingLayoutgetFooterLayout(){
returnfooterLayout;
}
protectedfinalLoadingLayoutgetHeaderLayout(){
returnheaderLayout;
}
protectedfinalintgetHeaderHeight(){
returnheaderHeight;
}
protectedfinalintgetMode(){
returnmode;
}
/**
*ImplementedbyderivedclasstoreturnwhethertheViewisinastate
*wheretheusercanPulltoRefreshbyscrollingdown.
*
*@returntrueiftheViewiscurrentlythecorrectstate(forexample,top
*ofaListView)
*/
protectedabstractbooleanisReadyForPullDown();
/**
*ImplementedbyderivedclasstoreturnwhethertheViewisinastate
*wheretheusercanPulltoRefreshbyscrollingup.
*
*@returntrueiftheViewiscurrentlyinthecorrectstate(forexample,
*bottomofaListView)
*/
protectedabstractbooleanisReadyForPullUp();
//===========================================================
//Methods
//===========================================================
protectedvoidresetHeader(){
state=PULL_TO_REFRESH;
isBeingDragged=false;
if(null!=headerLayout){
headerLayout.reset();
}
if(null!=footerLayout){
footerLayout.reset();
}
smoothScrollTo(0);
}
/**
*unlessspecialrequirementstocallthemethod,defaultcallthemethod
*{@link#setRefreshingInternal(booleandoScroll)}
*
*@paramdoScroll
*@parammode
*/
protectedvoidsetRefreshingInternal(booleandoScroll,intmode){
state=REFRESHING;
setRefreshLabel(mode);
if(null!=headerLayout){
headerLayout.refreshing();
}
if(doScroll){
smoothScrollTo(mode==MODE_PULL_DOWN_TO_REFRESH?-headerHeight
:headerHeight);
}
}
/**
*setlastrefreshtime
*
*@paramtime
*/
publicvoidsetRefreshTime(Stringtime){
TextViewmHeaderTimeView=(TextView)headerLayout
.findViewById(R.id.xlistview_header_time);
mHeaderTimeView.setText(time);
}
publicvoidsetRefreshTime(longtime){
TextViewmHeaderTimeView=(TextView)headerLayout
.findViewById(R.id.xlistview_header_time);
mHeaderTimeView.setText(TimeUtil.getChatTime(time));
}
protectedvoidsetRefreshingInternal(booleandoScroll){
state=REFRESHING;
setRefreshLabel(currentMode);
if(null!=footerLayout){
footerLayout.refreshing();
}
if(null!=headerLayout){
headerLayout.refreshing();
}
if(doScroll){
smoothScrollTo(currentMode==MODE_PULL_DOWN_TO_REFRESH?-headerHeight
:headerHeight);
}
}
privatevoidsetRefreshLabel(intmode){
if(mode==MODE_PULL_DOWN_TO_REFRESH){
setRefreshLabel("涓嬫媺鍒锋柊","閲婃斁绔嬪嵆鍒锋柊","姝e湪鍒锋柊");
}
if(mode==MODE_PULL_UP_TO_REFRESH){
setRefreshLabel("涓婃媺鑾峰彇鏇村","鏉惧紑鏄剧ず鏇村","姝e湪鍔犺浇");
}
}
protectedfinalvoidsetHeaderScroll(inty){
scrollTo(0,y);
}
protectedfinalvoidsmoothScrollTo(inty){
if(null!=currentSmoothScrollRunnable){
currentSmoothScrollRunnable.stop();
}
if(this.getScrollY()!=y){
this.currentSmoothScrollRunnable=newSmoothScrollRunnable(
handler,getScrollY(),y);
handler.post(currentSmoothScrollRunnable);
}
}
publicvoidinit(intmode){
//LoadingViewStrings
StringpullLabel=context
.getString(R.string.pull_to_refresh_pull_label);
StringrefreshingLabel=context
.getString(R.string.pull_to_refresh_refreshing_label);
StringreleaseLabel=context
.getString(R.string.pull_to_refresh_release_label);
//AddLoadingViews
if(mode==MODE_PULL_DOWN_TO_REFRESH||mode==MODE_BOTH){
headerLayout=newLoadingLayout(context,MODE_PULL_DOWN_TO_REFRESH,releaseLabel,pullLabel,refreshingLabel);
addView(headerLayout,0,newLinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT));
measureView(headerLayout);
headerHeight=headerLayout.getMeasuredHeight();
}
if(mode==MODE_PULL_UP_TO_REFRESH||mode==MODE_BOTH){
footerLayout=newLoadingLayout(context,MODE_PULL_UP_TO_REFRESH,releaseLabel,pullLabel,refreshingLabel);
addView(footerLayout,newLinearLayout.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
measureView(footerLayout);
headerHeight=footerLayout.getMeasuredHeight();
}
//StyleablesfromXML
if(null!=headerLayout){
//headerLayout.setTextColor(Color.BLACK);
}
if(null!=footerLayout){
//footerLayout.setTextColor(Color.BLACK);
}
//HideLoadingViews
switch(mode){
caseMODE_BOTH:
setPadding(0,-headerHeight,0,-headerHeight);
break;
caseMODE_PULL_UP_TO_REFRESH:
setPadding(0,0,0,-headerHeight);
break;
caseMODE_PULL_DOWN_TO_REFRESH:
default:
setPadding(0,-headerHeight,0,0);
break;
}
//Ifwe'renotusingMODE_BOTH,thenjustsetcurrentModetocurrent
//mode
if(mode!=MODE_BOTH){
currentMode=mode;
}
this.mode=mode;
}
privatevoidinit(Contextcontext,AttributeSetattrs){
this.context=context;
setOrientation(LinearLayout.VERTICAL);
touchSlop=ViewConfiguration.getTouchSlop();
//RefreshableView
//Bypassingtheattrs,wecanaddListView/GridViewparamsviaXML
refreshableView=this.createRefreshableView(context,attrs);
this.addRefreshableView(context,refreshableView);
}
privateContextcontext;
privatevoidmeasureView(Viewchild){
ViewGroup.LayoutParamsp=child.getLayoutParams();
if(p==null){
p=newViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
intchildWidthSpec=ViewGroup.getChildMeasureSpec(0,0+0,p.width);
intlpHeight=p.height;
intchildHeightSpec;
if(lpHeight>0){
childHeightSpec=MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
}else{
childHeightSpec=MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec,childHeightSpec);
}
/**
*ActionsaPullEvent
*
*@returntrueiftheEventhasbeenhandled,falseiftherehasbeenno
*change
*/
privatebooleanpullEvent(){
finalintnewHeight;
finalintoldHeight=this.getScrollY();
switch(currentMode){
caseMODE_PULL_UP_TO_REFRESH:
newHeight=Math.round(Math.max(initialMotionY-lastMotionY,0)
/FRICTION);
//newHeight=Math.round((initialMotionY-lastMotionY)/
//FRICTION);
break;
caseMODE_PULL_DOWN_TO_REFRESH:
default:
newHeight=Math.round(Math.min(initialMotionY-lastMotionY,0)
/FRICTION);
//newHeight=Math.round((initialMotionY-lastMotionY)/
//FRICTION);
break;
}
setHeaderScroll(newHeight);
if(newHeight!=0){
if(state==PULL_TO_REFRESH&&headerHeight<Math.abs(newHeight)){
state=RELEASE_TO_REFRESH;
switch(currentMode){
caseMODE_PULL_UP_TO_REFRESH:
footerLayout.releaseToRefresh();
break;
caseMODE_PULL_DOWN_TO_REFRESH:
headerLayout.releaseToRefresh();
break;
}
returntrue;
}elseif(state==RELEASE_TO_REFRESH
&&headerHeight>=Math.abs(newHeight)){
state=PULL_TO_REFRESH;
switch(currentMode){
caseMODE_PULL_UP_TO_REFRESH:
footerLayout.pullToRefresh();
break;
caseMODE_PULL_DOWN_TO_REFRESH:
headerLayout.pullToRefresh();
break;
}
returntrue;
}
}
returnoldHeight!=newHeight;
}
privatebooleanisReadyForPull(){
switch(mode){
caseMODE_PULL_DOWN_TO_REFRESH:
returnisReadyForPullDown();
caseMODE_PULL_UP_TO_REFRESH:
returnisReadyForPullUp();
caseMODE_BOTH:
returnisReadyForPullUp()||isReadyForPullDown();
}
returnfalse;
}
//===========================================================
//InnerandAnonymousClasses
//===========================================================
publicstaticinterfaceOnRefreshListener{
publicvoidonRefresh(intmode);
}
privateOnShowLayoutListeneronShowLayoutListener;
publicvoidsetOnShowLayoutListener(OnShowLayoutListenerlistener){
this.onShowLayoutListener=listener;
}
publicstaticinterfaceOnShowLayoutListener{
/**
*鏄鍚︽e湪鏄剧ず搴曢儴甯冨眬
*/
publicvoidonShow();
/**
*鏄鍚︽秷澶
*/
publicvoidonDismiss();
}
publicstaticinterfaceOnLastItemVisibleListener{
publicvoidonLastItemVisible();
}
@Override
publicvoidsetLongClickable(booleanlongClickable){
getRefreshableView().setLongClickable(longClickable);
}
}
主要代码都在上面贴出来了,当然还是一定要有demo
DEMO源码下载
这个源码里面我把PullToRefreshExpandableListView和PullToRefreshListView也都放进来了,一样的逻辑。希望对大家有用。如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!