android开发教程之实现listview下拉刷新和上拉刷新效果

代码如下:

public class PullToLoadListView extends ListView implements OnScrollListener {

private static final String TAG = PullToLoadListView.class.getSimpleName();

private static final int STATE_NON = 0;
 private static final int STATE_PULL_TO_REFRESH = 1;
 private static final int STATE_RELEASE_TO_REFRESH = 2;
 private static final int STATE_REFRESHING = 3;

private int state;

private int firstVisibleItem;
 private int lastVisisibleItem;

private float prevY = 0;

private View headerView;
 private View footerView;

// header widgets
 private ProgressBar headerProgressBar;
 private ImageView headerImageArrow;
 private TextView headerText;
 private RotateAnimation headerArrowAnim;
 private RotateAnimation headerArrowReverseAnim;
 // footer widgets
 private ProgressBar footerProgressBar;
 private TextView footerText;

private boolean headerIsHanding = false;
 private boolean footerIsHanding = false;

private int headerHeight;
 private int footerHeight;

private ResetAnimation resetAnim;

private OnLoadingListener onLoadingListener;

private OnScrollListener onScrollListener;

public PullToLoadListView(Context context) {
  super(context);
  init(context);
 }

public PullToLoadListView(Context context, AttributeSet attrs) {
  super(context, attrs);
  init(context);
 }

private void init(Context context) {
  state = STATE_NON;
  firstVisibleItem = 0;
  lastVisisibleItem = 0;

LayoutInflater inflater = LayoutInflater.from(context);
  headerView = inflater.inflate(R.layout.view_pull_header, null);
  footerView = inflater.inflate(R.layout.view_pull_footer, null);

headerProgressBar = (ProgressBar) headerView.findViewById(R.id.progressbar);
  headerImageArrow = (ImageView) headerView.findViewById(R.id.arrow);
  headerText = (TextView) headerView.findViewById(R.id.text);
  headerArrowAnim = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  headerArrowAnim.setDuration(300);
  headerArrowAnim.setFillAfter(true);
  headerArrowReverseAnim = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
  headerArrowReverseAnim.setDuration(300);
  headerArrowReverseAnim.setFillAfter(true);

footerProgressBar = (ProgressBar) footerView.findViewById(R.id.progressbar);
  footerText = (TextView) footerView.findViewById(R.id.text);

measureView(headerView);
  measureView(footerView);
  headerHeight = headerView.getMeasuredHeight();
  footerHeight = footerView.getMeasuredHeight();
  headerView.setPadding(0, -1 * headerView.getMeasuredHeight(), 0, 0);
  footerView.setPadding(0, -1 * footerView.getMeasuredHeight(), 0, 0);
  headerView.invalidate();
  footerView.invalidate();
  addHeaderView(headerView, null, false);
  addFooterView(footerView, null, false);

super.setOnScrollListener(this);
 }

private void measureView(View view) {
  ViewGroup.LayoutParams lp = view.getLayoutParams();
  if(lp == null) {
   lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  }
  int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
  int childHeightSpec;
  if(lp.height > 0) {
   childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY);
  } else {
   childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  }
  view.measure(childWidthSpec, childHeightSpec);
 }

private void resetHeader() {
  //  headerView.setPadding(0, -1 * headerHeight, 0, 0);
  resetAnim = new ResetAnimation(headerView, headerHeight, headerView.getPaddingTop());
  resetAnim.start();
 }

private void resetFooter() {
  resetAnim = new ResetAnimation(footerView, footerHeight, footerView.getPaddingTop());
  resetAnim.start();
 }

private void changeHeaderViewByState(int state) {
  if(this.state == state) {
   return ;
  }
  int prevState = this.state;
  this.state = state;

switch(state) {
  case STATE_NON:
   headerProgressBar.setVisibility(View.INVISIBLE);
   headerImageArrow.setVisibility(View.VISIBLE);
   headerImageArrow.clearAnimation();
   headerText.setText("Pull Down To Refresh");
   break;
  case STATE_PULL_TO_REFRESH:
   headerProgressBar.setVisibility(View.INVISIBLE);
   headerImageArrow.setVisibility(View.VISIBLE);
   headerText.setText("Pull Down To Refresh");
   if(prevState == STATE_RELEASE_TO_REFRESH) {
    headerImageArrow.startAnimation(headerArrowReverseAnim);
   } else {
    headerImageArrow.clearAnimation();
   }
   break;
  case STATE_RELEASE_TO_REFRESH:
   headerProgressBar.setVisibility(View.INVISIBLE);
   headerImageArrow.setVisibility(View.VISIBLE);
   headerImageArrow.startAnimation(headerArrowAnim);
   headerText.setText("Release To Refresh");
   break;
  case STATE_REFRESHING:
   headerProgressBar.setVisibility(View.VISIBLE);
   headerImageArrow.setVisibility(View.INVISIBLE);
   headerImageArrow.clearAnimation();
   headerText.setText("Refreshing");
   break;
  default:
   break;
  }
 }

private void changeFooterViewByState(int state) {
  if(this.state == state) {
   return ;
  }
  this.state = state;

switch(state) {
  case STATE_NON:
   footerProgressBar.setVisibility(View.INVISIBLE);
   footerText.setText("Pull Up To Refresh");
   break;
  case STATE_PULL_TO_REFRESH:
   footerProgressBar.setVisibility(View.INVISIBLE);
   footerText.setText("Pull Up To Refresh");
   break;
  case STATE_RELEASE_TO_REFRESH:
   footerProgressBar.setVisibility(View.INVISIBLE);
   footerText.setText("Release To Refresh");
   break;
  case STATE_REFRESHING:
   footerProgressBar.setVisibility(View.VISIBLE);
   footerText.setText("Refreshing");
   break;
  default:
   break;
  }
 }

@Override
 public void setOnScrollListener(OnScrollListener l) {
  this.onScrollListener = l;
 }

public void setOnLoadingListener(OnLoadingListener onLoadingListener) {
  this.onLoadingListener = onLoadingListener;
 }

public void loadCompleted() {
  if(headerIsHanding) {
   changeHeaderViewByState(STATE_NON);
   resetHeader();
   headerIsHanding = false;
  }
  if(footerIsHanding) {
   changeFooterViewByState(STATE_NON);
   resetFooter();
   footerIsHanding = false;
  }
 }

private void handleMoveHeaderEvent(MotionEvent ev) {
  headerIsHanding = true;
  float tempY = ev.getRawY();
  float vector = tempY - prevY;
  vector /= 2;
  prevY = tempY;
  if(vector > 0) {
   int newPadding = (int) (headerView.getPaddingTop() + vector);
   newPadding = Math.min(newPadding, headerHeight / 2);
   headerView.setPadding(0, newPadding, 0, 0);
   if(state != STATE_REFRESHING) {
    if(newPadding > 0) {
     changeHeaderViewByState(STATE_RELEASE_TO_REFRESH);
    } else {
     changeHeaderViewByState(STATE_PULL_TO_REFRESH);
    }
   }
  } else {
   if(state == STATE_RELEASE_TO_REFRESH || state == STATE_PULL_TO_REFRESH) {
    int newPadding = (int) (headerView.getPaddingTop() + vector);
    newPadding = Math.max(newPadding, -1 * headerHeight);
    headerView.setPadding(0, newPadding, 0, 0);
    if(newPadding <= -1 * headerHeight) {
     changeHeaderViewByState(STATE_NON);
     headerIsHanding = false;
    } else if(newPadding <= 0) {
     changeHeaderViewByState(STATE_PULL_TO_REFRESH);
    } else {

}
   }
  }
 }

private void handleMoveFooterEvent(MotionEvent ev) {
  footerIsHanding = true;
  float tempY = ev.getRawY();
  float vector = tempY - prevY;
  vector /= 2;
  prevY = tempY;
  if(vector < 0) {
   int newPadding = (int) (footerView.getPaddingTop() - vector);
   if(newPadding > 0) {
    newPadding = 0;
   }
   footerView.setPadding(0, newPadding, 0, 0);
   if(state != STATE_REFRESHING) {
    if(newPadding < 0) {
     changeFooterViewByState(STATE_PULL_TO_REFRESH);
    } else {
     changeFooterViewByState(STATE_RELEASE_TO_REFRESH);
    }
   }
  } else {
   int newPadding = (int) (footerView.getPaddingTop() - vector);
   newPadding = Math.min(newPadding, footerHeight);
   footerView.setPadding(0, newPadding, 0, 0);
   if(newPadding <= -1 * footerHeight) {
    changeFooterViewByState(STATE_NON);
    footerIsHanding = false;
   } else if(newPadding < 0) {
    changeFooterViewByState(STATE_PULL_TO_REFRESH);
   }
  }
 }

@Override
 public boolean onTouchEvent(MotionEvent ev) {
  switch(ev.getAction()) {
  case MotionEvent.ACTION_DOWN:
   prevY = ev.getRawY();
   break;
  case MotionEvent.ACTION_UP:
   if(state == STATE_RELEASE_TO_REFRESH) {
    if(headerIsHanding) {
     changeHeaderViewByState(STATE_REFRESHING);
     if(onLoadingListener != null) {
      onLoadingListener.onLoadNew();
     }
    }
    if(footerIsHanding) {
     changeFooterViewByState(STATE_REFRESHING);
     if(onLoadingListener != null) {
      onLoadingListener.onLoadMore();
     }
    }
   } else if(state == STATE_PULL_TO_REFRESH) {
    if(headerIsHanding) {
     changeHeaderViewByState(STATE_NON);
     resetHeader();
     headerIsHanding = false;
    }
    if(footerIsHanding) {
     changeFooterViewByState(STATE_NON);
     resetFooter();
     footerIsHanding = false;
    }
   } else if(state == STATE_NON) {
    headerIsHanding = false;
    footerIsHanding = false;
   } else {
    // state == STATE_REFRESHING
    // ignore
   }
   break;
  case MotionEvent.ACTION_MOVE:
   if(resetAnim == null || !resetAnim.run) {

if(state != STATE_REFRESHING) {
     Adapter adapter = getAdapter();
     if(adapter == null) {
      handleMoveHeaderEvent(ev);
     } else {
      final int count = adapter.getCount();
      if(count <= 0) {
       handleMoveHeaderEvent(ev);
      } else {
       float tempY = ev.getRawY();
       float vector = tempY - prevY;
       if(firstVisibleItem == 0 && lastVisisibleItem == count - 1) {
        if(headerIsHanding) {
         handleMoveHeaderEvent(ev);
        } else if(footerIsHanding) {
         handleMoveFooterEvent(ev);
        } else {
         if(vector > 0) {
          handleMoveHeaderEvent(ev);
         } else if(vector < 0) {
          handleMoveFooterEvent(ev);
         } else {
          // ignore vector == 0
         }
        }
       } else if(firstVisibleItem == 0 && vector > 0) {
        handleMoveHeaderEvent(ev);
       } else if(lastVisisibleItem == count - 1 && vector < 0) {
        handleMoveFooterEvent(ev);
       } else {
        // ignore
       }
      }
     }
    }
   }
   break;
  default:
   break;
  }
  return super.onTouchEvent(ev);
 }

@Override
 public void onScrollStateChanged(AbsListView view, int scrollState) {
  if(onScrollListener != null) {
   onScrollListener.onScrollStateChanged(view, scrollState);
  }
 }

@Override
 public void onScroll(AbsListView view, int firstVisibleItem,
   int visibleItemCount, int totalItemCount) {
  this.firstVisibleItem = firstVisibleItem;
  this.lastVisisibleItem = firstVisibleItem + visibleItemCount - 1;
  if(onScrollListener != null) {
   onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
  }
 }

static class ResetAnimation extends Thread {

static final int DURATION = 600;

static final int INTERVAL = 5;

View view;
  int orignalHeight;
  int paddingTop;

boolean run = false;

ResetAnimation(View view, int orignalHeight, int paddingTop) {
   this.view = view;
   this.orignalHeight = orignalHeight;
   this.paddingTop = paddingTop;
  }

public void run() {
   run = true;
   int total = orignalHeight * 2 + paddingTop;
   int timeTotal = DURATION / INTERVAL;
   int piece = total / timeTotal;
   int time = 0;
   final View view = this.view;
   final int paddingTop = this.paddingTop;
   do {
    final int nextPaddingTop = paddingTop - time * piece;
    view.post(new Runnable() {
     public void run() {
      view.setPadding(0, nextPaddingTop, 0, 0);
      view.postInvalidate();
     }
    });
    try {
     sleep(INTERVAL);
    } catch (InterruptedException e) {
     e.printStackTrace();
    }
    time ++;
   } while(time < timeTotal);
   run = false;
  }
 }

public interface OnLoadingListener {

public void onLoadNew();

public void onLoadMore();
 }

}

(0)

相关推荐

  • Android下拉刷新ListView——RTPullListView(demo)

    下拉刷新在越来越多的App中使用,已经形成一种默认的用户习惯,遇到列表显示的内容时,用户已经开始习惯性的拉拉.在交互习惯上已经形成定性.之前在我的文章<IOS学习笔记34-EGOTableViewPullRefresh实现下拉刷新>中介绍过如何在IOS上实现下拉刷新的功能.今天主要介绍下在Android上实现下拉刷新的Demo,下拉控件参考自Github上开源项目PullToRefresh,并做简单修改.最终效果如下:                         工程结构如下: 使用过程中

  • Android中使用RecyclerView实现下拉刷新和上拉加载

    推荐阅读:使用RecyclerView添加Header和Footer的方法                       RecyclerView的使用之HelloWorld RecyclerView 是Android L版本中新添加的一个用来取代ListView的SDK,它的灵活性与可替代性比listview更好.本文给大家介绍如何为RecyclerView添加下拉刷新和上拉加载,过去在ListView当中添加下拉刷新和上拉加载是非常方便的利用addHeaderView和addFooterVie

  • Android RecyclerView实现下拉刷新和上拉加载

    RecyclerView已经出来很久了,许许多多的项目都开始从ListView转战RecyclerView,那么,上拉加载和下拉刷新是一件很有必要的事情. 在ListView上,我们可以通过自己添加addHeadView和addFootView去添加头布局和底部局实现自定义的上拉和下拉,或者使用一些第三方库来简单的集成,例如Android-pulltorefresh或者android-Ultra-Pull-to-Refresh,后者的自定义更强,但需要自己实现上拉加载. 而在下面我们将用两种方式

  • Android PullToRefreshLayout下拉刷新控件的终结者

    说到下拉刷新控件,网上版本有很多,很多软件也都有下拉刷新功能.有一个叫XListView的,我看别人用过,没看过是咋实现的,看这名字估计是继承自ListView修改的,不过效果看起来挺丑的,也没什么扩展性,太单调了.看了QQ2014的列表下拉刷新,发现挺好看的,我喜欢,贴一下图看一下qq的下拉刷新效果: 不错吧?嗯,是的.一看就知道实现方式不一样.咱们今天就来实现一个下拉刷新控件.由于有时候不仅仅是ListView需要下拉刷新,ExpandableListView和GridView也有这个需求,

  • Android下拉刷新上拉加载控件(适用于所有View)

    前面写过一篇关于下拉刷新控件的文章下拉刷新控件终结者:PullToRefreshLayout,后来看到好多人还有上拉加载更多的需求,于是就在前面下拉刷新控件的基础上进行了改进,加了上拉加载的功能.不仅如此,我已经把它改成了对所有View都通用!可以随心所欲使用这两个功能~~ 我做了一个大集合的demo,实现了ListView.GridView.ExpandableListView.ScrollView.WebView.ImageView.TextView的下拉刷新和上拉加载.后面会提供demo的

  • Android自定义实现顶部粘性下拉刷新效果

    本文实例为大家分享了Android实现顶部粘性下拉刷新效果的具体代码,供大家参考,具体内容如下 学习:视频地址 activity_view_mv代码 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://sche

  • Android官方下拉刷新控件SwipeRefreshLayout使用详解

    可能开发安卓的人大多数都用过很多下拉刷新的开源组件,但是今天用了官方v4支持包的SwipeRefreshLayout觉得效果也蛮不错的,特拿出来分享. 简介: SwipeRefreshLayout组件只接受一个子组件:即需要刷新的那个组件.它使用一个侦听机制来通知拥有该组件的监听器有刷新事件发生,换句话说我们的Activity必须实现通知的接口.该Activity负责处理事件刷新和刷新相应的视图.一旦监听者接收到该事件,就决定了刷新过程中应处理的地方.如果要展示一个"刷新动画",它必须

  • Android下拉刷新完全解析,教你如何一分钟实现下拉刷新功能(附源码)

    最近项目中需要用到ListView下拉刷新的功能,一开始想图省事,在网上直接找一个现成的,可是尝试了网上多个版本的下拉刷新之后发现效果都不怎么理想.有些是因为功能不完整或有Bug,有些是因为使用起来太复杂,十全十美的还真没找到.因此我也是放弃了在网上找现成代码的想法,自己花功夫编写了一种非常简单的下拉刷新实现方案,现在拿出来和大家分享一下.相信在阅读完本篇文章之后,大家都可以在自己的项目中一分钟引入下拉刷新功能. 首先讲一下实现原理.这里我们将采取的方案是使用组合View的方式,先自定义一个布局

  • Android实现上拉加载更多以及下拉刷新功能(ListView)

    首先为大家介绍Andorid5.0原生下拉刷新简单实现. 先上效果图: 相对于上一个19.1.0版本中的横条效果好看了很多.使用起来也很简单. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" and

  • android下拉刷新ListView的介绍和实现代码

    大致上,我们发现,下拉刷新的列表和一般列表的区别是,当滚动条在顶端的时候,再往下拉动就会把整个列表拉下来,显示出松开刷新的提示.由此可以看出,在构建这个下拉刷新的组件的时候,只用继承ListView,然后重写onTouchEvent就能实现.还有就是要能在xml布局文件中引用,还需要一个参数为Context,AttributeSet的构造函数. 表面上的功能大概就这些了.另一方面,刷新的行为似乎还没有定义,在刷新前做什么,刷新时要做什么,刷新完成后要做什么,这些行为写入一个接口中,然后让组件去实

随机推荐