码迷,mamicode.com
首页 > 其他好文 > 详细

自定义下拉刷新ListView

时间:2015-04-28 15:36:05      阅读:208      评论:0      收藏:0      [点我收藏+]

标签:

 

PullToRefreshListView

原理:
下拉刷新ListView无非就是对普通的List View添加一个HeaderView,然后通过对ListView onTouchEvent来获取当前下拉刷新的状态。然后去改变HeaderView的状态。

  1. 自定义ListView,在构造方法中去添加HeaderView 通过ListView.addHeaderView()去添加HeaderView的时候,HeaderView会显示在屏幕的最初位置,我们需要它默认的时候是在屏幕的上方,这样默认时是不可见的,但是我们下拉ListView的时候,它就能够显示出来。这就要通过设置HeaderViewpadding来实现它的隐藏。注意:View的显示最初要经过Measure测量宽高,我们在构造方法去添加的时候,该View可能并没有被测量,所以在获取HeaderView高度的时候会为0,这时候我们要手动的去测量一下HeaderView

 

/** 当前状态 */ 
 private State mState = State.ORIGNAL; 
 
 public PullToRefreshListView(Context context, AttributeSet attrs, 
         int defStyle) { 
     super(context, attrs, defStyle); 
     initView(context); 
 } 
 
 public PullToRefreshListView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     initView(context); 
 } 
 
 public PullToRefreshListView(Context context) { 
     super(context); 
     initView(context); 
 } 
 
 private void initView(Context context) { 
     LayoutInflater inflater = (LayoutInflater) context 
             .getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
 
     mHeader = inflater.inflate(R.layout.pull_to_refresh_header, null); 
     iv_arrow = (ImageView) mHeader.findViewById(R.id.iv_arrow); 
     pb_refresh = (ProgressBar) mHeader.findViewById(R.id.pb_refresh); 
     tv_title = (TextView) mHeader.findViewById(R.id.tv_title); 
     tv_time = (TextView) mHeader.findViewById(R.id.tv_time); 
 
     measureHeaderView(mHeader); 
 
     mHeaderHeight = mHeader.getMeasuredHeight(); 
     // To make header view above the window, so use -mHeaderHeight. 
     mHeader.setPadding(0, -mHeaderHeight, 0, 0); 
 
     mHeader.invalidate(); 
 
     addHeaderView(mHeader); 
 } 
 
 /**下拉刷新所有的状态 */ 
 public enum State { 
     ORIGNAL, PULL_TO_REFRESH, REFRESHING, RELEASE_TO_REFRESH; 
 }

2.重写onTouchEvent,来监听手指的下拉

 public boolean onTouchEvent(MotionEvent ev) { 
     int y = (int) ev.getRawY(); 
     int action = ev.getAction(); 
     switch (action) { 
     case MotionEvent.ACTION_DOWN: 
         //记录手指点下的位置 
         downPositionY = y; 
         break; 
     case MotionEvent.ACTION_MOVE: 
         //手指当前滑动的位置 
         currentPositionY = y; 
         //手指移动的距离,由于HeaderView高度固定,但是手指下拉的高度可以最大为屏幕的高度,如手指下拉屏幕高度时,HeaderView会很难看,所以我们让下拉的距离进行一个缩放。 
         pullDistance = (currentPositionY - downPositionY) / RATIO; 
 
         if (mState == State.REFRESHING) { 
             break; 
         } else if (mState == State.ORIGNAL && pullDistance > 0) { 
             //如果现在处理起始的状态,并且距离大于0,就说明是下拉了,这时候状态需要变为下拉刷新的状态 
             mState = State.PULL_TO_REFRESH; 
             changeState(); 
         } else if (mState == State.PULL_TO_REFRESH 
                 && pullDistance > mHeaderHeight) { 
             //当时为下拉刷新的状态,但是下拉的距离大于HeaderView的高度。这时状态要变为松手即可刷新 
             mState = State.RELEASE_TO_REFRESH; 
             changeState(); 
         } else if (mState == State.RELEASE_TO_REFRESH) { 
         //释放刷新时有三种情况,一是我继续下啦,这时候不用管,因为继续下拉还是释放刷新。二是我手指往上移动,此时HeaderView不完全可见,这时候状态要改变为下拉刷新了。三是我手指上移的很厉害,导致HeaderView完全不可见了,这是状态要改变为起始状态。 
             if (pullDistance < 0) { 
                 // 如果当时状态为松手刷新,但是这时候我并没有松手,而是直接将手指往上移动,移动回手指最先的位置,这时候状态要变为起始状态。 
                 mState = State.ORIGNAL; 
                 changeState(); 
             } else if (pullDistance < mHeaderHeight) { 
                 //手指上移,但是并没有移动到HeaderView完全不可见,这时候要将状态改变为下拉刷新 
                 mState = State.PULL_TO_REFRESH; 
                 isBack = true; 
                 changeState(); 
             } 
 
         } 
 
         //在移动的过程中不断的去改版Padding的值,控制其显示的大小 
         if (mState != State.REFRESHING) { 
             mHeader.setPadding(0, (int) (pullDistance - mHeaderHeight), 0, 
                     0); 
         } 
 
         break; 
     case MotionEvent.ACTION_UP: 
         if (mState == State.REFRESHING) { 
             //如果当前已经是正在刷新中了,再去下拉就不要处理了 
             break; 
         } else if (mState == State.PULL_TO_REFRESH) { 
             //显现下拉刷新时,松手了,这时候要将其改为起始状态 
             mState = State.ORIGNAL; 
         } else if (mState == State.RELEASE_TO_REFRESH) { 
             //松手刷新时松手了,这时候状态要变为正在刷新中。 
             mState = State.REFRESHING; 
         } else { 
             break; 
         } 
         changeState(); 
         break; 
 
     default: 
         break; 
     } 
 
     return super.onTouchEvent(ev); 
 }

3.上面的写法仍有些问题。就是我们在onTouchEventMove里面对移动的距离进行了判断,但是ListView本身就是一个可以上下滑动的组件,如果我们直接这样判断,那ListView本上上下滑动的功能就被我们给抹去了。

 @Override 
 public boolean onTouchEvent(MotionEvent ev) { 
     int y = (int) ev.getRawY(); 
     int action = ev.getAction(); 
     switch (action) { 
     case MotionEvent.ACTION_DOWN: 
         downPositionY = y; 
         break; 
     case MotionEvent.ACTION_MOVE: 
         //一定要加上这句话,来判断当前是否可以下拉刷新 
         if (!isCanPullToRefresh) { 
             break; 
         } 
         ..... 
         break;

而对于isCanPullToRefresh的判断是通过ListView.setOnScrollListener去进行判断当前第一个可见条目是不是ListView的第一个条目,只有第一个条目在最顶端位置的时候才可以进行下拉刷新。

 super.setOnScrollListener(new OnScrollListener() { 
 
     @Override 
     public void onScrollStateChanged(AbsListView view, int scrollState) { 
     } 
 
     @Override 
     public void onScroll(AbsListView view, int firstVisibleItem, 
             int visibleItemCount, int totalItemCount) { 
 
         if (firstVisibleItem == 0) { 
             isCanPullToRefresh = true; 
         } else { 
             isCanPullToRefresh = false; 
         } 
     } 
 });

4.提供刷新接口

 public interface OnRefreshListener { 
     abstract void onRefresh(); 
 }

5.ChangeState方法

 private void changeState() { 
     //在该方法中对mState进行判断,根据不同状态作出处理,并且去调用刷新方法 
 } 
 
 /** 数据刷新完成后需要调用此方法去恢复装填 */ 
 @SuppressWarnings("deprecation") 
 public void onRefreshComplete() { 
     mState = State.ORIGNAL; 
     changeState(); 
     tv_time.setText(getResources().getString(R.string.update_time) 
             + new Date().toLocaleString()); 
 }

 

LoadMoreListView

原理:
滑动到底部自动加载更多的ListView,无非就是通过对其滑动过程进行监听,一旦滑动到底部的时候我们就去加载新的数据。通过对ListView添加FooterView,然后在不同的状态控制它的显示与隐藏。

  1. 自定义ListView的子类,在构造方法中去添加FooterView.
public class LoadMoreListView extends ListView { 
 
public LoadMoreListView(Context context, AttributeSet attrs, int defStyle) { 
    super(context, attrs, defStyle); 
    init(context); 
} 
 
public LoadMoreListView(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    init(context); 
} 
 
public LoadMoreListView(Context context) { 
    super(context); 
    init(context); 
} 
 
private void init(Context context) { 
    mFooterView = View.inflate(context, R.layout.load_more_footer, null); 
    addFooterView(mFooterView); 
    hideFooterView(); 
}

2.监听滑动状态,通过setOnScrollListener即可实现对状态的监听。

 private void init(Context context) { 
     mFooterView = View.inflate(context, R.layout.load_more_footer, null); 
     addFooterView(mFooterView); 
     hideFooterView(); 
     //为了防止在使用时调用setOnScrollListener会覆盖此时设置的Listener,我们在此使用super.setOnScrollListenr() 
     super.setOnScrollListener(superOnScrollListener); 
 }

3.ScrollListener中去判断当前滑动的状态。从而依据不同的状态去控制FooterView的显示与隐藏。

 private OnScrollListener superOnScrollListener = new OnScrollListener() { 
 
     @Override 
     public void onScrollStateChanged(AbsListView view, int scrollState) { 
         mCurrentScrollState = scrollState; 
     } 
 
     @Override 
     public void onScroll(AbsListView view, int firstVisibleItem, 
             int visibleItemCount, int totalItemCount) { 
         if (visibleItemCount == totalItemCount) { 
             //此时说明当前ListView所有的条目比较少,不足一屏 
             hideFooterView(); 
         } else if (!mIsLoading 
                 && (firstVisibleItem + visibleItemCount >= totalItemCount) 
                 && mCurrentScrollState != SCROLL_STATE_IDLE) { 
             //当第一个可见的条目位置加上当前也所有可见的条目数 等于 ListView当前总的条目数时,就说明已经滑动到了底部,这时候就要去显示FooterView。 
             showFooterView(); 
             mIsLoading = true; 
             if (mOnLoadMoreListener != null) { 
                 mOnLoadMoreListener.onLoadMore(); 
             } 
         } 
     } 
 };

4.提供自动加载更多的接口。

 public interface OnLoadMoreListener { 
     /** 
      * Load more data. 
      */ 
     void onLoadMore(); 
 }

在使用的时候,与ListView使用方法相同,只需调用setOnLoadMoreListener对其设置OnLoadMoreListener即可,然后在数据加载完成后调用onLoadComplete方法去恢复状态。

 

自定义下拉刷新ListView

标签:

原文地址:http://www.cnblogs.com/huangzx/p/4462844.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!