[强悍]listview下拉刷新,上拉加载更多组件版

感谢作者,原项目地址:https://github.com/wedcel/PullToRefresh_MoreLoad_PerfectVersion

当然,也弄到了网盘分享,下载更便捷:链接: http://pan.baidu.com/s/1sjv5T05 密码: j34s

首先先贴上组件CustomListView的源码:

  1 package com.maomao.beautymovie.widget;
  2 
  3 import java.text.SimpleDateFormat;
  4 import java.util.Date;
  5 import java.util.Locale;
  6 
  7 import com.maomao.beautymovie.R;
  8 
  9 import android.content.Context;
 10 import android.util.AttributeSet;
 11 import android.util.Log;
 12 import android.view.LayoutInflater;
 13 import android.view.MotionEvent;
 14 import android.view.View;
 15 import android.view.ViewGroup;
 16 import android.view.animation.Interpolator;
 17 import android.view.animation.LinearInterpolator;
 18 import android.view.animation.RotateAnimation;
 19 import android.widget.AbsListView;
 20 import android.widget.AbsListView.OnScrollListener;
 21 import android.widget.BaseAdapter;
 22 import android.widget.ImageView;
 23 import android.widget.LinearLayout;
 24 import android.widget.ListView;
 25 import android.widget.ProgressBar;
 26 import android.widget.TextView;
 27 
 28 /**
 29  * ListView下拉刷新和加载更多<p>
 30  * 
 31  * <strong>变更说明:</strong>
 32  * <p>默认如果设置了OnRefreshListener接口和OnLoadMoreListener接口,<br>并且不为null,则打开这两个功能了。
 33  * <p>剩余两个Flag:mIsAutoLoadMore(是否自动加载更多)和
 34  * <br>mIsMoveToFirstItemAfterRefresh(下拉刷新后是否显示第一条Item)
 35  * 
 36  * <p><strong>有改进意见,请发送到俺的邮箱哈~ 多谢各位小伙伴了!^_^</strong>
 37  * 
 38  * @date 2013-11-11 下午10:09:26
 39  * @change JohnWatson 
 40  * @mail xxzhaofeng5412@gmail.com
 41  * @version 1.0
 42  */
 43 public class CustomListView extends ListView implements OnScrollListener {
 44 
 45     /**  显示格式化日期模板   */
 46     private final static String DATE_FORMAT_STR = "yyyy年MM月dd日 HH:mm";
 47     
 48     /**  实际的padding的距离与界面上偏移距离的比例   */
 49     private final static int RATIO = 3;
 50     
 51     private final static int RELEASE_TO_REFRESH = 0;
 52     private final static int PULL_TO_REFRESH = 1;
 53     private final static int REFRESHING = 2;
 54     private final static int DONE = 3;
 55     private final static int LOADING = 4;
 56     
 57     /**  加载中   */
 58     private final static int ENDINT_LOADING = 1;
 59     /**  手动完成刷新   */
 60     private final static int ENDINT_MANUAL_LOAD_DONE = 2;
 61     /**  自动完成刷新   */
 62     private final static int ENDINT_AUTO_LOAD_DONE = 3;
 63     
 64     /**    0:RELEASE_TO_REFRESH;
 65      * <p> 1:PULL_To_REFRESH;
 66      * <p> 2:REFRESHING;
 67      * <p> 3:DONE;
 68      * <p> 4:LOADING */
 69     private int mHeadState;
 70     /**    0:完成/等待刷新 ;
 71      * <p> 1:加载中  */
 72     private int mEndState;
 73     
 74     // ================================= 功能设置Flag ================================
 75     
 76     /**  可以加载更多?   */
 77     private boolean mCanLoadMore = false;
 78     /**  可以下拉刷新?   */
 79     private boolean mCanRefresh = false;
 80     /**  可以自动加载更多吗?(注意,先判断是否有加载更多,如果没有,这个flag也没有意义)   */
 81     private boolean mIsAutoLoadMore = true;
 82     /** 下拉刷新后是否显示第一条Item    */
 83     private boolean mIsMoveToFirstItemAfterRefresh = false;
 84     
 85     public boolean isCanLoadMore() {
 86         return mCanLoadMore;
 87     }
 88     
 89     public void setCanLoadMore(boolean pCanLoadMore) {
 90         mCanLoadMore = pCanLoadMore;
 91         if(mCanLoadMore && getFooterViewsCount() == 0){
 92             addFooterView();
 93         }
 94     }
 95     
 96     public boolean isCanRefresh() {
 97         return mCanRefresh;
 98     }
 99     
100     public void setCanRefresh(boolean pCanRefresh) {
101         mCanRefresh = pCanRefresh;
102     }
103     
104     public boolean isAutoLoadMore() {
105         return mIsAutoLoadMore;
106     }
107 
108     public void setAutoLoadMore(boolean pIsAutoLoadMore) {
109         mIsAutoLoadMore = pIsAutoLoadMore;
110     }
111         
112     public boolean isMoveToFirstItemAfterRefresh() {
113         return mIsMoveToFirstItemAfterRefresh;
114     }
115 
116     public void setMoveToFirstItemAfterRefresh(
117             boolean pIsMoveToFirstItemAfterRefresh) {
118         mIsMoveToFirstItemAfterRefresh = pIsMoveToFirstItemAfterRefresh;
119     }
120     
121     // ============================================================================
122 
123     private LayoutInflater mInflater;
124 
125     private LinearLayout mHeadView;
126     private TextView mTipsTextView;
127     private TextView mLastUpdatedTextView;
128     private ImageView mArrowImageView;
129     private ProgressBar mProgressBar;
130     
131     private View mEndRootView;
132     private ProgressBar mEndLoadProgressBar;
133     private TextView mEndLoadTipsTextView;
134 
135     /**  headView动画   */
136     private RotateAnimation mArrowAnim;
137     /**  headView反转动画   */
138     private RotateAnimation mArrowReverseAnim;
139  
140     /** 用于保证startY的值在一个完整的touch事件中只被记录一次    */
141     private boolean mIsRecored;
142 
143     private int mHeadViewWidth;
144     private int mHeadViewHeight;
145 
146     private int mStartY;
147     private boolean mIsBack;
148     
149     private int mFirstItemIndex;
150     private int mLastItemIndex;
151     private int mCount;
152     private boolean mEnoughCount;//足够数量充满屏幕? 
153     
154     private OnRefreshListener mRefreshListener;
155     private OnLoadMoreListener mLoadMoreListener;
156 
157     public CustomListView(Context pContext, AttributeSet pAttrs) {
158         super(pContext, pAttrs);
159         init(pContext);
160     }
161 
162     public CustomListView(Context pContext) {
163         super(pContext);
164         init(pContext);
165     }
166 
167     public CustomListView(Context pContext, AttributeSet pAttrs, int pDefStyle) {
168         super(pContext, pAttrs, pDefStyle);
169         init(pContext);
170     }
171 
172     /**
173      * 初始化操作
174      * @param pContext 
175      * @date 2013-11-20 下午4:10:46
176      * @change JohnWatson
177      * @version 1.0
178      */
179     private void init(Context pContext) {
180         setCacheColorHint(pContext.getResources().getColor(R.color.transparent));
181         mInflater = LayoutInflater.from(pContext);
182 
183         addHeadView();
184         
185         setOnScrollListener(this);
186 
187         initPullImageAnimation(0);
188     }
189 
190     /**
191      * 添加下拉刷新的HeadView 
192      * @date 2013-11-11 下午9:48:26
193      * @change JohnWatson
194      * @version 1.0
195      */
196     private void addHeadView() {
197         mHeadView = (LinearLayout) mInflater.inflate(R.layout.listview_header, null);
198 
199         mArrowImageView = (ImageView) mHeadView
200                 .findViewById(R.id.head_arrowImageView);
201         mArrowImageView.setMinimumWidth(70);
202         mArrowImageView.setMinimumHeight(50);
203         mProgressBar = (ProgressBar) mHeadView
204                 .findViewById(R.id.head_progressBar);
205         mTipsTextView = (TextView) mHeadView.findViewById(
206                 R.id.head_tipsTextView);
207         mLastUpdatedTextView = (TextView) mHeadView
208                 .findViewById(R.id.head_lastUpdatedTextView);
209 
210         measureView(mHeadView);
211         mHeadViewHeight = mHeadView.getMeasuredHeight();
212         mHeadViewWidth = mHeadView.getMeasuredWidth();
213         
214         mHeadView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
215         mHeadView.invalidate();
216 
217         Log.v("size", "" + mHeadViewWidth + " height:"
218                 + mHeadViewHeight);
219 
220         addHeaderView(mHeadView, null, false);
221         
222         mHeadState = DONE;
223     }
224     
225     /**
226      * 添加加载更多FootView
227      * @date 2013-11-11 下午9:52:37
228      * @change JohnWatson
229      * @version 1.0
230      */
231     private void addFooterView() {
232         mEndRootView = mInflater.inflate(R.layout.listfooter_more, null);
233         mEndRootView.setVisibility(View.VISIBLE);
234         mEndLoadProgressBar = (ProgressBar) mEndRootView
235                 .findViewById(R.id.pull_to_refresh_progress);
236         mEndLoadTipsTextView = (TextView) mEndRootView.findViewById(R.id.load_more);
237         mEndRootView.setOnClickListener(new View.OnClickListener() {
238 
239             @Override
240             public void onClick(View v) {
241                 if(mCanLoadMore){
242                     if(mCanRefresh){
243                         // 当可以下拉刷新时,如果FootView没有正在加载,并且HeadView没有正在刷新,才可以点击加载更多。
244                         if(mEndState != ENDINT_LOADING && mHeadState != REFRESHING){
245                             mEndState = ENDINT_LOADING;
246                             onLoadMore();
247                         }
248                     }else if(mEndState != ENDINT_LOADING){
249                         // 当不能下拉刷新时,FootView不正在加载时,才可以点击加载更多。
250                         mEndState = ENDINT_LOADING;
251                         onLoadMore();
252                     }
253                 }
254             }
255         });
256         
257         addFooterView(mEndRootView);
258         
259         if(mIsAutoLoadMore){
260             mEndState = ENDINT_AUTO_LOAD_DONE;
261         }else{
262             mEndState = ENDINT_MANUAL_LOAD_DONE;
263         }
264     }
265 
266     /**
267      * 实例化下拉刷新的箭头的动画效果 
268      * @param pAnimDuration 动画运行时长
269      * @date 2013-11-20 上午11:53:22
270      * @change JohnWatson
271      * @version 1.0
272      */
273     private void initPullImageAnimation(final int pAnimDuration) {
274         
275         int _Duration;
276         
277         if(pAnimDuration > 0){
278             _Duration = pAnimDuration;
279         }else{
280             _Duration = 250;
281         }
282 //        Interpolator _Interpolator;
283 //        switch (pAnimType) {
284 //        case 0:
285 //            _Interpolator = new AccelerateDecelerateInterpolator();
286 //            break;
287 //        case 1:
288 //            _Interpolator = new AccelerateInterpolator();
289 //            break;
290 //        case 2:
291 //            _Interpolator = new AnticipateInterpolator();
292 //            break;
293 //        case 3:
294 //            _Interpolator = new AnticipateOvershootInterpolator();
295 //            break;
296 //        case 4:
297 //            _Interpolator = new BounceInterpolator();
298 //            break;
299 //        case 5:
300 //            _Interpolator = new CycleInterpolator(1f);
301 //            break;
302 //        case 6:
303 //            _Interpolator = new DecelerateInterpolator();
304 //            break;
305 //        case 7:
306 //            _Interpolator = new OvershootInterpolator();
307 //            break;
308 //        default:
309 //            _Interpolator = new LinearInterpolator();
310 //            break;
311 //        }
312         
313         Interpolator _Interpolator = new LinearInterpolator();
314         
315         mArrowAnim = new RotateAnimation(0, -180,
316                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,
317                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);
318         mArrowAnim.setInterpolator(_Interpolator);
319         mArrowAnim.setDuration(_Duration);
320         mArrowAnim.setFillAfter(true);
321 
322         mArrowReverseAnim = new RotateAnimation(-180, 0,
323                 RotateAnimation.RELATIVE_TO_SELF, 0.5f,
324                 RotateAnimation.RELATIVE_TO_SELF, 0.5f);
325         mArrowReverseAnim.setInterpolator(_Interpolator);
326         mArrowReverseAnim.setDuration(_Duration);
327         mArrowReverseAnim.setFillAfter(true);
328     }
329 
330     /**
331      * 测量HeadView宽高(注意:此方法仅适用于LinearLayout,请读者自己测试验证。)
332      * @param pChild 
333      * @date 2013-11-20 下午4:12:07
334      * @change JohnWatson
335      * @version 1.0
336      */
337     private void measureView(View pChild) {
338         ViewGroup.LayoutParams p = pChild.getLayoutParams();
339         if (p == null) {
340             p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
341                     ViewGroup.LayoutParams.WRAP_CONTENT);
342         }
343         int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
344         int lpHeight = p.height;
345 
346         int childHeightSpec;
347         if (lpHeight > 0) {
348             childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
349                     MeasureSpec.EXACTLY);
350         } else {
351             childHeightSpec = MeasureSpec.makeMeasureSpec(0,
352                     MeasureSpec.UNSPECIFIED);
353         }
354         pChild.measure(childWidthSpec, childHeightSpec);
355     }
356     
357     /**
358      *为了判断滑动到ListView底部没
359      */
360     @Override
361     public void onScroll(AbsListView pView, int pFirstVisibleItem,
362             int pVisibleItemCount, int pTotalItemCount) {
363         mFirstItemIndex = pFirstVisibleItem;
364         mLastItemIndex = pFirstVisibleItem + pVisibleItemCount - 2;
365         mCount = pTotalItemCount - 2;
366         if (pTotalItemCount > pVisibleItemCount ) {
367             mEnoughCount = true;
368 //            endingView.setVisibility(View.VISIBLE);
369         } else {
370             mEnoughCount = false;
371         }
372     }
373 
374     /**
375      *这个方法,可能有点乱,大家多读几遍就明白了。
376      */
377     @Override
378     public void onScrollStateChanged(AbsListView pView, int pScrollState) {
379         if(mCanLoadMore){// 存在加载更多功能
380             if (mLastItemIndex ==  mCount && pScrollState == SCROLL_STATE_IDLE) {
381                 //SCROLL_STATE_IDLE=0,滑动停止
382                 if (mEndState != ENDINT_LOADING) {
383                     if(mIsAutoLoadMore){// 自动加载更多,我们让FootView显示 “更    多”
384                         if(mCanRefresh){
385                             // 存在下拉刷新并且HeadView没有正在刷新时,FootView可以自动加载更多。
386                             if(mHeadState != REFRESHING){
387                                 // FootView显示 : 更    多  ---> 加载中...
388                                 mEndState = ENDINT_LOADING;
389                                 onLoadMore();
390                                 changeEndViewByState();
391                             }
392                         }else{// 没有下拉刷新,我们直接进行加载更多。
393                             // FootView显示 : 更    多  ---> 加载中...
394                             mEndState = ENDINT_LOADING;
395                             onLoadMore();
396                             changeEndViewByState();
397                         }
398                     }else{// 不是自动加载更多,我们让FootView显示 “点击加载”
399                         // FootView显示 : 点击加载  ---> 加载中...
400                         mEndState = ENDINT_MANUAL_LOAD_DONE;
401                         changeEndViewByState();
402                     }
403                 }
404             }
405         }else if(mEndRootView != null && mEndRootView.getVisibility() == VISIBLE){
406             // 突然关闭加载更多功能之后,我们要移除FootView。
407             System.out.println("this.removeFooterView(endRootView);...");
408             mEndRootView.setVisibility(View.GONE);
409             this.removeFooterView(mEndRootView);
410         }
411     }
412 
413     /**
414      * 改变加载更多状态
415      * @date 2013-11-11 下午10:05:27
416      * @change JohnWatson
417      * @version 1.0
418      */
419     private void  changeEndViewByState() {
420         if (mCanLoadMore) {
421             //允许加载更多
422             switch (mEndState) {
423             case ENDINT_LOADING://刷新中
424                 
425                 // 加载中...
426                 if(mEndLoadTipsTextView.getText().equals(
427                         R.string.p2refresh_doing_end_refresh)){
428                     break;
429                 }
430                 mEndLoadTipsTextView.setText(R.string.p2refresh_doing_end_refresh);
431                 mEndLoadTipsTextView.setVisibility(View.VISIBLE);
432                 mEndLoadProgressBar.setVisibility(View.VISIBLE);
433                 break;
434             case ENDINT_MANUAL_LOAD_DONE:// 手动刷新完成
435                 
436                 // 点击加载
437                 mEndLoadTipsTextView.setText(R.string.p2refresh_end_click_load_more);
438                 mEndLoadTipsTextView.setVisibility(View.VISIBLE);
439                 mEndLoadProgressBar.setVisibility(View.GONE);
440                 
441                 mEndRootView.setVisibility(View.VISIBLE);
442                 break;
443             case ENDINT_AUTO_LOAD_DONE:// 自动刷新完成
444                 
445                 // 更    多
446                 mEndLoadTipsTextView.setText(R.string.p2refresh_end_load_more);
447                 mEndLoadTipsTextView.setVisibility(View.VISIBLE);
448                 mEndLoadProgressBar.setVisibility(View.GONE);
449                 
450                 mEndRootView.setVisibility(View.VISIBLE);
451                 break;
452             default:
453                 // 原来的代码是为了: 当所有item的高度小于ListView本身的高度时,
454                 // 要隐藏掉FootView,大家自己去原作者的代码参考。
455                 
456 //                if (enoughCount) {                    
457 //                    endRootView.setVisibility(View.VISIBLE);
458 //                } else {
459 //                    endRootView.setVisibility(View.GONE);
460 //                }
461                 break;
462             }
463         }
464     }
465     
466     /**
467      *原作者的,我没改动,请读者自行优化。
468      */
469     public boolean onTouchEvent(MotionEvent event) {
470         
471         if (mCanRefresh) {
472             if(mCanLoadMore && mEndState == ENDINT_LOADING){
473                 // 如果存在加载更多功能,并且当前正在加载更多,默认不允许下拉刷新,必须加载完毕后才能使用。
474                 return super.onTouchEvent(event);
475             }
476             
477             switch (event.getAction()) {
478             
479             case MotionEvent.ACTION_DOWN:
480                 if (mFirstItemIndex == 0 && !mIsRecored) {
481                     mIsRecored = true;
482                     mStartY = (int) event.getY();
483                 }
484                 break;
485 
486             case MotionEvent.ACTION_UP:
487 
488                 if (mHeadState != REFRESHING && mHeadState != LOADING) {
489                     if (mHeadState == DONE) {
490                         
491                     }
492                     if (mHeadState == PULL_TO_REFRESH) {
493                         mHeadState = DONE;
494                         changeHeaderViewByState();
495                     }
496                     if (mHeadState == RELEASE_TO_REFRESH) {
497                         mHeadState = REFRESHING;
498                         changeHeaderViewByState();
499                         onRefresh();
500                     }
501                 }
502 
503                 mIsRecored = false;
504                 mIsBack = false;
505 
506                 break;
507 
508             case MotionEvent.ACTION_MOVE:
509                 int tempY = (int) event.getY();
510 
511                 if (!mIsRecored && mFirstItemIndex == 0) {
512                     mIsRecored = true;
513                     mStartY = tempY;
514                 }
515 
516                 if (mHeadState != REFRESHING && mIsRecored && mHeadState != LOADING) {
517 
518                     // 保证在设置padding的过程中,当前的位置一直是在head,
519                     // 否则如果当列表超出屏幕的话,当在上推的时候,列表会同时进行滚动
520                     // 可以松手去刷新了
521                     if (mHeadState == RELEASE_TO_REFRESH) {
522 
523                         setSelection(0);
524 
525                         // 往上推了,推到了屏幕足够掩盖head的程度,但是还没有推到全部掩盖的地步
526                         if (((tempY - mStartY) / RATIO < mHeadViewHeight)
527                                 && (tempY - mStartY) > 0) {
528                             mHeadState = PULL_TO_REFRESH;
529                             changeHeaderViewByState();
530                         }
531                         // 一下子推到顶了
532                         else if (tempY - mStartY <= 0) {
533                             mHeadState = DONE;
534                             changeHeaderViewByState();
535                         }
536                         // 往下拉了,或者还没有上推到屏幕顶部掩盖head的地步
537                     }
538                     // 还没有到达显示松开刷新的时候,DONE或者是PULL_To_REFRESH状态
539                     if (mHeadState == PULL_TO_REFRESH) {
540 
541                         setSelection(0);
542 
543                         // 下拉到可以进入RELEASE_TO_REFRESH的状态
544                         if ((tempY - mStartY) / RATIO >= mHeadViewHeight) {
545                             mHeadState = RELEASE_TO_REFRESH;
546                             mIsBack = true;
547                             changeHeaderViewByState();
548                         } else if (tempY - mStartY <= 0) {
549                             mHeadState = DONE;
550                             changeHeaderViewByState();
551                         }
552                     }
553 
554                     if (mHeadState == DONE) {
555                         if (tempY - mStartY > 0) {
556                             mHeadState = PULL_TO_REFRESH;
557                             changeHeaderViewByState();
558                         }
559                     }
560 
561                     if (mHeadState == PULL_TO_REFRESH) {
562                         mHeadView.setPadding(0, -1 * mHeadViewHeight
563                                 + (tempY - mStartY) / RATIO, 0, 0);
564 
565                     }
566 
567                     if (mHeadState == RELEASE_TO_REFRESH) {
568                         mHeadView.setPadding(0, (tempY - mStartY) / RATIO
569                                 - mHeadViewHeight, 0, 0);
570                     }
571                 }
572                 break;
573             }
574         }
575 
576         return super.onTouchEvent(event);
577     }
578 
579     /**
580      * 当HeadView状态改变时候,调用该方法,以更新界面
581      * @date 2013-11-20 下午4:29:44
582      * @change JohnWatson
583      * @version 1.0
584      */
585     private void changeHeaderViewByState() {
586         switch (mHeadState) {
587         case RELEASE_TO_REFRESH:
588             mArrowImageView.setVisibility(View.VISIBLE);
589             mProgressBar.setVisibility(View.GONE);
590             mTipsTextView.setVisibility(View.VISIBLE);
591             mLastUpdatedTextView.setVisibility(View.VISIBLE);
592 
593             mArrowImageView.clearAnimation();
594             mArrowImageView.startAnimation(mArrowAnim);
595             // 松开刷新
596             mTipsTextView.setText(R.string.p2refresh_release_refresh);
597 
598             break;
599         case PULL_TO_REFRESH:
600             mProgressBar.setVisibility(View.GONE);
601             mTipsTextView.setVisibility(View.VISIBLE);
602             mLastUpdatedTextView.setVisibility(View.VISIBLE);
603             mArrowImageView.clearAnimation();
604             mArrowImageView.setVisibility(View.VISIBLE);
605             // 是由RELEASE_To_REFRESH状态转变来的
606             if (mIsBack) {
607                 mIsBack = false;
608                 mArrowImageView.clearAnimation();
609                 mArrowImageView.startAnimation(mArrowReverseAnim);
610                 // 下拉刷新
611                 mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);
612             } else {
613                 // 下拉刷新
614                 mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);
615             }
616             break;
617 
618         case REFRESHING:
619             mHeadView.setPadding(0, 0, 0, 0);
620             
621             // 华生的建议: 实际上这个的setPadding可以用动画来代替。我没有试,但是我见过。其实有的人也用Scroller可以实现这个效果,
622             // 我没时间研究了,后期再扩展,这个工作交给小伙伴你们啦~ 如果改进了记得发到我邮箱噢~
623             // 本人邮箱: xxzhaofeng5412@gmail.com
624             
625             mProgressBar.setVisibility(View.VISIBLE);
626             mArrowImageView.clearAnimation();
627             mArrowImageView.setVisibility(View.GONE);
628             // 正在刷新...
629             mTipsTextView.setText(R.string.p2refresh_doing_head_refresh);
630             mLastUpdatedTextView.setVisibility(View.VISIBLE);
631 
632             break;
633         case DONE:
634             mHeadView.setPadding(0, -1 * mHeadViewHeight, 0, 0);
635             
636             // 此处可以改进,同上所述。
637             
638             mProgressBar.setVisibility(View.GONE);
639             mArrowImageView.clearAnimation();
640             mArrowImageView.setImageResource(R.drawable.arrow);
641             // 下拉刷新
642             mTipsTextView.setText(R.string.p2refresh_pull_to_refresh);
643             mLastUpdatedTextView.setVisibility(View.VISIBLE);
644 
645             break;
646         }
647     }
648 
649     /**
650      * 下拉刷新监听接口
651      * @date 2013-11-20 下午4:50:51
652      * @change JohnWatson
653      * @version 1.0
654      */
655     public interface OnRefreshListener {
656         public void onRefresh();
657     }
658     
659     /**
660      * 加载更多监听接口
661      * @date 2013-11-20 下午4:50:51
662      * @change JohnWatson
663      * @version 1.0
664      */
665     public interface OnLoadMoreListener {
666         public void onLoadMore();
667     }
668     
669     public void setOnRefreshListener(OnRefreshListener pRefreshListener) {
670         if(pRefreshListener != null){
671             mRefreshListener = pRefreshListener;
672             mCanRefresh = true;
673         }
674     }
675 
676     public void setOnLoadListener(OnLoadMoreListener pLoadMoreListener) {
677         if(pLoadMoreListener != null){
678             mLoadMoreListener = pLoadMoreListener;
679             mCanLoadMore = true;
680             if(mCanLoadMore && getFooterViewsCount() == 0){
681                 addFooterView();
682             }
683         }
684     }
685     
686     /**
687      * 正在下拉刷新
688      * @date 2013-11-20 下午4:45:47
689      * @change JohnWatson
690      * @version 1.0
691      */
692     private void onRefresh() {
693         if (mRefreshListener != null) {
694             mRefreshListener.onRefresh();
695         }
696     }
697     
698     /**
699      * 下拉刷新完成
700      * @date 2013-11-20 下午4:44:12
701      * @change JohnWatson
702      * @version 1.0
703      */
704     public void onRefreshComplete() {
705         // 下拉刷新后是否显示第一条Item 
706         if(mIsMoveToFirstItemAfterRefresh)setSelection(0);
707         
708         mHeadState = DONE;
709         // 最近更新: Time
710         mLastUpdatedTextView.setText(
711                 getResources().getString(R.string.p2refresh_refresh_lasttime) + 
712                 new SimpleDateFormat(DATE_FORMAT_STR, Locale.CHINA).format(new Date()));
713         changeHeaderViewByState();
714     }
715 
716     /**
717      * 正在加载更多,FootView显示 : 加载中...
718      * @date 2013-11-20 下午4:35:51
719      * @change JohnWatson
720      * @version 1.0
721      */
722     private void onLoadMore() {
723         if (mLoadMoreListener != null) {
724             // 加载中...
725             mEndLoadTipsTextView.setText(R.string.p2refresh_doing_end_refresh);
726             mEndLoadTipsTextView.setVisibility(View.VISIBLE);
727             mEndLoadProgressBar.setVisibility(View.VISIBLE);
728             
729             mLoadMoreListener.onLoadMore();
730         }
731     }
732 
733     /**
734      * 加载更多完成 
735      * @date 2013-11-11 下午10:21:38
736      * @change JohnWatson
737      * @version 1.0
738      */
739     public void onLoadMoreComplete() {
740         if(mIsAutoLoadMore){
741             mEndState = ENDINT_AUTO_LOAD_DONE;
742         }else{
743             mEndState = ENDINT_MANUAL_LOAD_DONE;
744         }
745         changeEndViewByState();
746     }
747     
748     /**
749      * 主要更新一下刷新时间啦!
750      * @param adapter
751      * @date 2013-11-20 下午5:35:51
752      * @change JohnWatson
753      * @version 1.0
754      */
755     public void setAdapter(BaseAdapter adapter) {
756         // 最近更新: Time
757         mLastUpdatedTextView.setText(
758                 getResources().getString(R.string.p2refresh_refresh_lasttime) + 
759                 new SimpleDateFormat(DATE_FORMAT_STR, Locale.CHINA).format(new Date()));
760         super.setAdapter(adapter);
761     }
762 
763 }
View Code

在布局里添加即可:

 1 <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     xmlns:tools="http://schemas.android.com/tools"
 3     android:id="@+id/swipe_container"
 4     android:layout_width="match_parent"
 5     android:layout_height="match_parent"
 6     tools:context=".MainActivity" >
 7 
 8 
 9     <com.maomao.beautymovie.widget.CustomListView
10         android:id="@+id/movielistview"
11         android:layout_width="match_parent"
12         android:layout_height="match_parent"
13         android:choiceMode="singleChoice"
14         android:descendantFocusability="blocksDescendants"
15         android:divider="@null"
16         android:scrollbars="none" >
17     </com.maomao.beautymovie.widget.CustomListView>
18 
19 </android.support.v4.widget.SwipeRefreshLayout>

在activity或fragment使用:

 1 package com.maomao.beautymovie.fragment;
 2 
 3 public class AllMovieFragment extends Fragment{
 4 
 5     private static final String TAG = "movieFragment";
 6     private SwipeRefreshLayout swipeLayout;
 7     private CustomListView movieListView;
 8     private MovieListAdapter movieListAdapter;
 9     private List<MovieBean> moviesLsit;
10     
11     public AllMovieFragment()
12     {
13     }
14 
15     public AllMovieFragment(List<MovieBean> moviesLsit)
16     {
17         this.moviesLsit = moviesLsit;
18     }
19     
20 
21     
22     @Override
23     public void onCreate(Bundle savedInstanceState) {
24         super.onCreate(savedInstanceState);
25 
26     }
27 
28     @SuppressLint("InlinedApi")
29     @Override
30     public View onCreateView(LayoutInflater inflater, ViewGroup container,
31             Bundle savedInstanceState) {
32         View view            = inflater.inflate(R.layout.allmoviefrag, container, false);
33         movieListView = (CustomListView)view.findViewById(R.id.movielistview);
34 
35         movieListAdapter = new MovieListAdapter(getActivity(), moviesLsit);
36         
37         movieListView.setAdapter(movieListAdapter); 
38         initListView();
39 
40         
41         
42         return view;
43     }
44 
45     
46     
47     public void initListView()
48     {
49         movieListView.setOnItemClickListener(new OnItemClickListener() {
50             
51 
52             @Override
53             public void onItemClick(AdapterView<?> parent, View view, int position,
54                     long id) {
55                 // 此处传回来的position和mAdapter.getItemId()获取的一致;
56                 //parent.getAdapter().getItem(position)
57                 MovieBean movieBean = (MovieBean)parent.getAdapter().getItem(position);
58                 Toast.makeText(getActivity(), movieBean.getMovieName(), Toast.LENGTH_SHORT).show();
59                 //Toast.makeText(getActivity(), "位置"+Integer.toString(position), Toast.LENGTH_SHORT).show();
60                 
61             }
62         });
63         
64         
65         movieListView.setOnLoadListener(new OnLoadMoreListener() {
66 
67             @Override
68             public void onLoadMore() {
69                 // TODO 加载更多
70                 Log.e(TAG, "onLoad");
71                 Toast.makeText(getActivity(), "load", Toast.LENGTH_SHORT).show();
72                 
73                 movieListView.postDelayed(new Runnable() {
74                 
75                                 @Override
76                                 public void run() {
77                                       moviesLsit.addAll(MyDataSource.addMovieDataSource());
78                                       movieListAdapter.notifyDataSetChanged();
79                               // 加载完后调用该方法
80                                       movieListView.onLoadMoreComplete();    //加载更多完成
81                                 }
82                             }, 5000);
83                 
84                         
85             }
86         });
87         
88         
89         //CustomListView简单易用,如下代码即可说明,可选择性的开关下拉刷新和加载更多,同时可在设置界面设置是否启动自动加载更多
90         //关闭下拉刷新
91         movieListView.setCanRefresh(false);
92         //启动加载更多
93         movieListView.setCanLoadMore(true);
94         //启动自动加载更多
95         movieListView.setAutoLoadMore(false);
96         
97     }
98     
99 }

感谢作者。

原文地址:https://www.cnblogs.com/ning1121/p/4377807.html