[强悍]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", "width:" + 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 }
在布局里添加即可:
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 }
感谢作者。