Android中实现List下拉刷新

今天,我以如何在Android中实现下拉刷新介绍下主要实现步骤:

1.重写ListView。ListView中有一个addHeaderView()的方法用来在顶部添加一个view。

2.让ListView实现触摸事件和滚动事件,来根据状态动态改变view。

3.利用回调接口来更新ListView。

下面看具体代码:

public class RefreshListView extends ListView implements OnScrollListener{

 private View headerView;
 private int headerViewHeight;
 private int firstVisibleItem;//当前第一个可见的Item的位置
 private boolean mark;//标记:当前是否在ListView的最顶端按下的
 private int startY;//按下时的Y值
 private int state;//当前的状态
 private final int NONE = 0;//正常状态
 private final int PULL = 1;//提示下拉状态
 private final int RELESE = 2;//松开释放的状态
 private final int REFLASHING = 3;//正在刷新的状态
 private int scrollState;//当前滚动状态
 private RefreshInterface refreshInterface;
 public RefreshListView(Context context) {
  super(context);
  initView(context);
 }
 
 public RefreshListView(Context context, AttributeSet attrs) {
  super(context, attrs);
  initView(context);
 }
 public RefreshListView(Context context, AttributeSet attrs,int defStyle) {
  // TODO Auto-generated constructor stub
  super(context,attrs,defStyle);
  initView(context);
 }
 
 /**
  * 初始化组件 添加顶部布局文件到ListView
  * @param context
  */
 private void initView(Context context){
  headerView = LayoutInflater.from(context).inflate(R.layout.header_listview, null);
  measureView(headerView);
  headerViewHeight = headerView.getMeasuredHeight();//此处需要通知父布局headerView占的宽高。
  topPadding(-headerViewHeight);
  this.addHeaderView(headerView);
  this.setOnScrollListener(this);
 }
 /**
  * 通知父布局view所占的宽高
  * @param view
  */
 private void measureView(View view){
  ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
  if(layoutParams == null){
   layoutParams = new ViewGroup.LayoutParams(
     ViewGroup.LayoutParams.MATCH_PARENT,
     ViewGroup.LayoutParams.MATCH_PARENT);
   
  }
  //获取宽高
  int width = ViewGroup.getChildMeasureSpec(0, 0,layoutParams.width);
  int height;
  int tempHeight = layoutParams.height;
  if(tempHeight > 0){
   height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
  }else{
   height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  }
  //填充View
  view.measure(width, height);
 }
 /**
  * 设置headerView的上边距
  * @param topPadding
  */
 private void topPadding(int topPadding){
  headerView.setPadding(headerView.getPaddingLeft(),
    topPadding ,
    headerView.getPaddingRight(),
    headerView.getPaddingBottom());
  headerView.invalidate();
 }

 
 @Override
 public void onScrollStateChanged(AbsListView view, int scrollState) {
  // TODO Auto-generated method stub
  this.scrollState = scrollState;
 }

 @Override
 public void onScroll(AbsListView view, int firstVisibleItem,
   int visibleItemCount, int totalItemCount) {
   this.firstVisibleItem = firstVisibleItem;
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {
   switch (event.getAction()) {
   //按下
   case MotionEvent.ACTION_DOWN:
    if(firstVisibleItem == 0){
     //第一项Item在最顶端
     mark = true;
     startY = (int)event.getY();
    }
    break;
   //弹起
   case MotionEvent.ACTION_UP:
    if(state == RELESE){
     state = REFLASHING;
     //加载最新数据
     reflashView();
     refreshInterface.onRefresh();
    }else if(state == PULL){
     state = NONE;
     mark = false; 
     reflashView();
    }
    break;
   //移动
   case MotionEvent.ACTION_MOVE:
    move(event);
    break;     
   default:
    break;
   }
  return super.onTouchEvent(event);
 }
 private void move(MotionEvent event){
  if(!mark){
   return;
  }
  int currentY = (int)event.getY();
  int space = currentY - startY;
  int topPadding = space - headerViewHeight;
  switch (state) {
  case NONE:
   if(space > 0){
    state = PULL;
    reflashView();
   }
   break;
  case PULL:
   topPadding(topPadding);
   if(space > headerViewHeight + 30 && scrollState == SCROLL_STATE_TOUCH_SCROLL){
    state = RELESE;
    reflashView();
   }   
   break;
  case RELESE:
   topPadding(topPadding);
   if(space < headerViewHeight + 30 ){
    state = PULL;
    reflashView();
   }else if(space <= 0){
    state = NONE;
    mark = false;
    reflashView();
   }
   break;
  default:
   break;
  }
 }
 //根据状态更新显示
 private void reflashView(){
  TextView textView = (TextView)findViewById(R.id.tip);
  ImageView arrow = (ImageView)findViewById(R.id.refresh_arrow);
  ProgressBar progress = (ProgressBar)findViewById(R.id.progress);
  RotateAnimation animationDown = new RotateAnimation(
    0,
    180,
    RotateAnimation.RELATIVE_TO_SELF,
    0.5f,
    RotateAnimation.RELATIVE_TO_SELF,
    0.5f);
  RotateAnimation animationUp = new RotateAnimation(
    180,
    0,
    RotateAnimation.RELATIVE_TO_SELF,
    0.5f,
    RotateAnimation.RELATIVE_TO_SELF,
    0.5f);
  animationDown.setDuration(500);
  animationDown.setFillAfter(true);
  animationUp.setDuration(500);
  animationUp.setFillAfter(true);  
  switch (state) {
  case NONE:
   topPadding(-headerViewHeight);
   arrow.clearAnimation();
   break;
  case PULL:
   arrow.setVisibility(View.VISIBLE);
   progress.setVisibility(View.GONE);
   textView.setText("下拉可以刷新");
   arrow.clearAnimation();
   arrow.setAnimation(animationUp);
  
   break;
  case RELESE:
   arrow.setVisibility(View.VISIBLE);
   progress.setVisibility(View.GONE);
   textView.setText("松开可以刷新");
   arrow.clearAnimation();
   arrow.setAnimation(animationDown);
   break;
  case REFLASHING:
   topPadding(50);
   arrow.setVisibility(View.GONE);
   progress.setVisibility(View.VISIBLE);
   textView.setText("正在刷新");
   arrow.clearAnimation();
   break;
  default:
   break;
  }
 }
 /**
  * 刷新完成
  */
 public void refreshComplete(){
  state = NONE;
  mark = false;
  TextView lastupdatetime = (TextView)findViewById(R.id.lastupdatetime);
  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
  Date date = new Date(System.currentTimeMillis());
  String time = format.format(date);
  lastupdatetime.setText(time);
  reflashView();
 }
 /**
  * 刷新数据接口
  */
 public interface RefreshInterface{
  public void onRefresh();
 }
 public void setInterface(RefreshInterface refreshInterface){
  this.refreshInterface = refreshInterface;
 }

}




你可能感兴趣的:(android,ListView)