zoukankan      html  css  js  c++  java
  • ListView的下拉刷新和上拉加载--XListView

    分析XListView的源码,是因为其他开源控件代码都太多了(主要很多细微的地方都不懂,只能理解个大概),这个控件只是在原生ListView的基础上添加Header和Footer,代码很简单,可以随便折腾。

    Github地址:Github上搜索这个就行-----XListView-Android


    看Header代码:

    /**
     * @file XListViewHeader.java
     * @create Apr 18, 2012 5:22:27 PM
     * @author Maxwin
     * @description XListView's header
     */
    package me.maxwin.view;
    
    import me.maxwin.R;
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.Gravity;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.RotateAnimation;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    
    public class XListViewHeader extends LinearLayout {
    	private LinearLayout mContainer;
    	private ImageView mArrowImageView;
    	private ProgressBar mProgressBar;
    	private TextView mHintTextView;
    	private int mState = STATE_NORMAL;
    
    	private Animation mRotateUpAnim;
    	private Animation mRotateDownAnim;
    	
    	private final int ROTATE_ANIM_DURATION = 180;
    
    	// 正常状态 (箭头不动,进度条隐藏)
    	public final static int STATE_NORMAL = 0;
    	// 准备状态 (箭头向上或者向下旋转,进度条隐藏)
    	public final static int STATE_READY = 1;
    	// 刷新状态 (箭头隐藏,进度条旋转)
    	public final static int STATE_REFRESHING = 2;
    
    	public XListViewHeader(Context context) {
    		super(context);
    		initView(context);
    	}
    
    	/**
    	 * @param context c
    	 * @param attrs a
    	 */
    	public XListViewHeader(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		initView(context);
    	}
    
    	/**
    	 * 初始化整个布局:箭头、时间文字、进度条
    	 * 布局宽为FILL_PARENT,Gravity为BOTTOM,这个是为了更新header高度的时候,布局始终在parent的底部
    	 * 箭头的旋转动画
    	 * @param context activity
    	 */
    	private void initView(Context context) {
    		// 初始情况,设置下拉刷新view高度为0
    		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
    				LayoutParams.MATCH_PARENT, 0);
    		mContainer = (LinearLayout) LayoutInflater.from(context).inflate(
    				R.layout.xlistview_header, null);
    		addView(mContainer, lp);
    		setGravity(Gravity.BOTTOM);
    
    		mArrowImageView = (ImageView)findViewById(R.id.xlistview_header_arrow);
    		mHintTextView = (TextView)findViewById(R.id.xlistview_header_hint_textview);
    		mProgressBar = (ProgressBar)findViewById(R.id.xlistview_header_progressbar);
    		
    		mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
    				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    				0.5f);
    		mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
    		mRotateUpAnim.setFillAfter(true);
    		mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
    				Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
    				0.5f);
    		mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
    		mRotateDownAnim.setFillAfter(true);
    	}
    
    	/**
    	 * 设置刷新的状态:STATE_NORMAL / STATE_READY / STATE_REFRESHING
    	 * 箭头和进度条的隐藏/显示 由上面的if语句判断
    	 * 状态之间的变化由switch语句判断
    	 * @param state state
    	 */
    	public void setState(int state) {
    		// 与之前状态一样,什么都不干
    		if (state == mState) return ;
    
    		/**
    		 * 正在刷新显示进度和文字
    		 * 否则显示箭头和文字
    		 * 也可以按自己需求做成别的样子
     		 */
    		if (state == STATE_REFRESHING) {	// 显示进度
    			mArrowImageView.clearAnimation();
    			mArrowImageView.setVisibility(View.INVISIBLE);
    			mProgressBar.setVisibility(View.VISIBLE);
    		} else {	// 显示箭头图片
    			mArrowImageView.setVisibility(View.VISIBLE);
    			mProgressBar.setVisibility(View.INVISIBLE);
    		}
    		
    		switch(state){
    		case STATE_NORMAL:
    			/**
    			 * mState 记录的是之前的状态
    			 * 这句代码的意思就是:由STATE_READY变为STATE_NORMAL
    			 * 箭头向下旋转
    			 */
    			if (mState == STATE_READY) {
    				mArrowImageView.startAnimation(mRotateDownAnim);
    			}
    
    			/**
    			 * STATE_REFRESHING 变为 STATE_NORMAL
    			 * 动画清除
    			 */
    			if (mState == STATE_REFRESHING) {
    				mArrowImageView.clearAnimation();
    			}
    			mHintTextView.setText(R.string.xlistview_header_hint_normal);
    			break;
    		case STATE_READY:
    			/**
    			 * STATE_REFRESHING 变为 STATE_READY (没有这个状态变化)
    			 * STATE_NORMAL 变为 STATE_READY
    			 * 箭头向上旋转
    			 */
    			if (mState != STATE_READY) {
    				mArrowImageView.clearAnimation();
    				mArrowImageView.startAnimation(mRotateUpAnim);
    				mHintTextView.setText(R.string.xlistview_header_hint_ready);
    			}
    			break;
    		case STATE_REFRESHING:
    			mHintTextView.setText(R.string.xlistview_header_hint_loading);
    			break;
    			default:
    		}
    		
    		mState = state;
    	}
    
    	/**
    	 * 设置头布局的高度
    	 * @param height h
    	 */
    	public void setVisibleHeight(int height) {
    		if (height < 0)
    			height = 0;
    		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer
    				.getLayoutParams();
    		lp.height = height;
    		mContainer.setLayoutParams(lp);
    	}
    
    	/**
    	 * 获取头布局的高度
    	 * @return h
    	 */
    	public int getVisibleHeight() {
    		return mContainer.getLayoutParams().height;
    	}
    
    }
    

      

    看Footer的代码:

    /**
     * @file XFooterView.java
     * @create Mar 31, 2012 9:33:43 PM
     * @author Maxwin
     * @description XListView's footer
     */
    package me.maxwin.view;
    
    import me.maxwin.R;
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.LinearLayout;
    import android.widget.TextView;
    
    /**
     * 上拉加载(显示出footer后,再继续往上拉才会出发上拉加载事件,或者直接点击footer)
     * 如果要做自动加载效果,可以自己监听ListView的滑动事件
     */
    public class XListViewFooter extends LinearLayout {
    	public final static int STATE_NORMAL = 0;
    	public final static int STATE_READY = 1;
    	public final static int STATE_LOADING = 2;
    
    	private Context mContext;
    
    	private View mContentView;
    	private View mProgressBar;
    	private TextView mHintView;
    	
    	public XListViewFooter(Context context) {
    		super(context);
    		initView(context);
    	}
    	
    	public XListViewFooter(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		initView(context);
    	}
    
    	/**
    	 * 设置上拉状态
    	 * @param state s
    	 */
    	public void setState(int state) {
    		mHintView.setVisibility(View.INVISIBLE);
    		mProgressBar.setVisibility(View.INVISIBLE);
    		mHintView.setVisibility(View.INVISIBLE);
    		/**
    		 * STATE_READY:只显示准备文字
    		 * STATE_LOADING:只显示进度条
    		 * STATE_NORMAL:只显示正常文字
    		 * 仍然可以根据自己需要调整
    		 */
    		if (state == STATE_READY) {
    			mHintView.setVisibility(View.VISIBLE);
    			mHintView.setText(R.string.xlistview_footer_hint_ready);
    		} else if (state == STATE_LOADING) {
    			mProgressBar.setVisibility(View.VISIBLE);
    		} else {
    			mHintView.setVisibility(View.VISIBLE);
    			mHintView.setText(R.string.xlistview_footer_hint_normal);
    		}
    	}
    
    	/**
    	 * 设置footer的margin值
    	 * @param height h
    	 */
    	public void setBottomMargin(int height) {
    		if (height < 0) return ;
    		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
    		lp.bottomMargin = height;
    		mContentView.setLayoutParams(lp);
    	}
    
    	/**
    	 * 获取footer的margin值
    	 * @return
    	 */
    	public int getBottomMargin() {
    		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
    		return lp.bottomMargin;
    	}
    	
    	
    	/**
    	 * 正常状态
    	 * normal status
    	 */
    	public void normal() {
    		mHintView.setVisibility(View.VISIBLE);
    		mProgressBar.setVisibility(View.GONE);
    	}
    	
    	
    	/**
    	 * 上拉加载状态
    	 * loading status 
    	 */
    	public void loading() {
    		mHintView.setVisibility(View.GONE);
    		mProgressBar.setVisibility(View.VISIBLE);
    	}
    	
    	/**
    	 * 隐藏footer,不需要上拉加载的时候
    	 * hide footer when disable pull load more
    	 */
    	public void hide() {
    		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
    		lp.height = 0;
    		mContentView.setLayoutParams(lp);
    	}
    	
    	/**
    	 * 显示footer
    	 * show footer
    	 */
    	public void show() {
    		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();
    		lp.height = LayoutParams.WRAP_CONTENT;
    		mContentView.setLayoutParams(lp);
    	}
    
    	/**
    	 * 初始化footer布局
    	 * @param context activity
    	 */
    	private void initView(Context context) {
    		mContext = context;
    		LinearLayout moreView = (LinearLayout)LayoutInflater.from(mContext).inflate(R.layout.xlistview_footer, null);
    		addView(moreView);
    		moreView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
    		
    		mContentView = moreView.findViewById(R.id.xlistview_footer_content);
    		mProgressBar = moreView.findViewById(R.id.xlistview_footer_progressbar);
    		mHintView = (TextView)moreView.findViewById(R.id.xlistview_footer_hint_textview);
    	}
    	
    	
    }
    

      

      

    看XListView的代码:

    /**
     * @file XListView.java
     * @package me.maxwin.view
     * @create Mar 18, 2012 6:28:41 PM
     * @author Maxwin
     * @description An ListView support (a) Pull down to refresh, (b) Pull up to load more.
     * 		Implement IXListViewListener, and see stopRefresh() / stopLoadMore().
     */
    package me.maxwin.view;
    
    import me.maxwin.R;
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewTreeObserver.OnGlobalLayoutListener;
    import android.view.animation.DecelerateInterpolator;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.ListAdapter;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.Scroller;
    import android.widget.TextView;
    
    public class XListView extends ListView implements OnScrollListener {
    
    	private float mLastY = -1; // save event y
    	private Scroller mScroller; // used for scroll back
    	private OnScrollListener mScrollListener; // user's scroll listener
    
    	// the interface to trigger refresh and load more.
    	private IXListViewListener mListViewListener;
    
    	// -- header view
    	private XListViewHeader mHeaderView;
    	// header view content, use it to calculate the Header's height. And hide it
    	// when disable pull refresh.
    	private RelativeLayout mHeaderViewContent;
    	private TextView mHeaderTimeView;
    	private int mHeaderViewHeight; // header view's height
    	private boolean mEnablePullRefresh = true;
    	private boolean mPullRefreshing = false; // is refreashing.
    
    	// -- footer view
    	private XListViewFooter mFooterView;
    	private boolean mEnablePullLoad;
    	private boolean mPullLoading;
    	private boolean mIsFooterReady = false;
    	
    	// total list items, used to detect is at the bottom of listview.
    	private int mTotalItemCount;
    
    	// for mScroller, scroll back from header or footer.
    	private int mScrollBack;
    	private final static int SCROLLBACK_HEADER = 0;
    	private final static int SCROLLBACK_FOOTER = 1;
    
    	private final static int SCROLL_DURATION = 400; // scroll back duration
    	private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px
    														// at bottom, trigger
    														// load more.
    	private final static float OFFSET_RADIO = 1.8f; // support iOS like pull
    													// feature.
    
    	public XListView(Context context) {
    		super(context);
    		initWithContext(context);
    	}
    
    	public XListView(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		initWithContext(context);
    	}
    
    	public XListView(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    		initWithContext(context);
    	}
    
    	/**
    	 * mScroller 用来处理滚动的
    	 * 初始化header,添加header到ListView,获取header的高度
    	 * 初始化footer,不添加到ListView,放在setAdapter里
    	 * @param context activity
    	 */
    	private void initWithContext(Context context) {
    		mScroller = new Scroller(context, new DecelerateInterpolator());
    		// XListView need the scroll event, and it will dispatch the event to
    		// user's listener (as a proxy).
    		super.setOnScrollListener(this);
    
    		// init header view
    		mHeaderView = new XListViewHeader(context);
    		mHeaderViewContent = (RelativeLayout) mHeaderView
    				.findViewById(R.id.xlistview_header_content);
    		mHeaderTimeView = (TextView) mHeaderView
    				.findViewById(R.id.xlistview_header_time);
    		addHeaderView(mHeaderView);
    
    		// init footer view
    		mFooterView = new XListViewFooter(context);
    
    		// init header height
    		mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(
    				new OnGlobalLayoutListener() {
    					@Override
    					public void onGlobalLayout() {
    						mHeaderViewHeight = mHeaderViewContent.getHeight();
    						getViewTreeObserver()
    								.removeGlobalOnLayoutListener(this);
    					}
    				});
    	}
    
    	/**
    	 * 先addFooter再setAdapter,避免footer不显示(我遇到过)
    	 * mIsFooterReady是判断footer添加过没有,footer只能添加一次
    	 * @param adapter a
    	 */
    	@Override
    	public void setAdapter(ListAdapter adapter) {
    		// make sure XListViewFooter is the last footer view, and only add once.
    		if (mIsFooterReady == false) {
    			mIsFooterReady = true;
    			addFooterView(mFooterView);
    		}
    		super.setAdapter(adapter);
    	}
    
    	/**
    	 * 设置是否可以下拉刷新
    	 *
    	 * enable or disable pull down refresh feature.
    	 * 
    	 * @param enable e
    	 */
    	public void setPullRefreshEnable(boolean enable) {
    		mEnablePullRefresh = enable;
    		if (!mEnablePullRefresh) { // disable, hide the content
    			mHeaderViewContent.setVisibility(View.INVISIBLE);
    		} else {
    			mHeaderViewContent.setVisibility(View.VISIBLE);
    		}
    	}
    
    	/**
    	 * 设置是否可以上拉加载
    	 *
    	 * enable or disable pull up load more feature.
    	 * 
    	 * @param enable e
    	 */
    	public void setPullLoadEnable(boolean enable) {
    		mEnablePullLoad = enable;
    		if (!mEnablePullLoad) {
    			mFooterView.hide();
    			mFooterView.setOnClickListener(null);
    			//make sure "pull up" don't show a line in bottom when listview with one page 
    			setFooterDividersEnabled(false);
    		} else {
    			mPullLoading = false;
    			mFooterView.show();
    			mFooterView.setState(XListViewFooter.STATE_NORMAL);
    			//make sure "pull up" don't show a line in bottom when listview with one page  
    			setFooterDividersEnabled(true);
    			// both "pull up" and "click" will invoke load more.
    			mFooterView.setOnClickListener(new OnClickListener() {
    				@Override
    				public void onClick(View v) {
    					startLoadMore();
    				}
    			});
    		}
    	}
    
    	/**
    	 * 停止下拉刷新,重置header
    	 * stop refresh, reset header view.
    	 */
    	public void stopRefresh() {
    		if (mPullRefreshing == true) {
    			mPullRefreshing = false;
    			resetHeaderHeight();
    		}
    	}
    
    	/**
    	 * 停止上拉加载,重置footer
    	 * stop load more, reset footer view.
    	 */
    	public void stopLoadMore() {
    		if (mPullLoading == true) {
    			mPullLoading = false;
    			mFooterView.setState(XListViewFooter.STATE_NORMAL);
    		}
    	}
    
    	/**
    	 * 设置上拉刷新的时间
    	 * set last refresh time
    	 * 
    	 * @param time
    	 */
    	public void setRefreshTime(String time) {
    		mHeaderTimeView.setText(time);
    	}
    
    	/**
    	 * 触发滑动事件(监听器需要实现OnXScrollListener)
    	 */
    	private void invokeOnScrolling() {
    		if (mScrollListener instanceof OnXScrollListener) {
    			OnXScrollListener l = (OnXScrollListener) mScrollListener;
    			l.onXScrolling(this);
    		}
    	}
    
    	/**
    	 * 更新header的高度
    	 * @param delta 手指拖动的距离
    	 */
    	private void updateHeaderHeight(float delta) {
    		// 更新header的高度 = 之前的高度 + delta
    		mHeaderView.setVisibleHeight((int) delta
    				+ mHeaderView.getVisibleHeight());
    
    		// 可以下拉刷新,并且不是正在刷新状态
    		if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头
    
    			/**
    			 * 更新后的高度 > header的初始高度了,状态变为准备状态
    			 * 否则,仍然是普通状态
    			 */
    			if (mHeaderView.getVisibleHeight() > mHeaderViewHeight) {
    				mHeaderView.setState(XListViewHeader.STATE_READY);
    			} else {
    				mHeaderView.setState(XListViewHeader.STATE_NORMAL);
    			}
    		}
    
    		/**
    		 * 这里是没有看懂的地方,为啥子????
    		 */
    		setSelection(0); // scroll to top each time
    	}
    
    	/**
    	 * 重置header的高度
    	 * header没有完全显示,什么都不做
    	 * header完全显示了,用mScroller实现滚动(从height到finalHeight - height),header刚好显示
    	 * reset header view's height.
    	 */
    	private void resetHeaderHeight() {
    		int height = mHeaderView.getVisibleHeight();
    		if (height == 0) // not visible.
    			return;
    		// refreshing and header isn't shown fully. do nothing.
    		if (mPullRefreshing && height <= mHeaderViewHeight) {
    			return;
    		}
    		int finalHeight = 0; // default: scroll back to dismiss header.
    		// is refreshing, just scroll back to show all the header.
    		if (mPullRefreshing && height > mHeaderViewHeight) {
    			finalHeight = mHeaderViewHeight;
    		}
    		mScrollBack = SCROLLBACK_HEADER;
    		mScroller.startScroll(0, height, 0, finalHeight - height,
    				SCROLL_DURATION);
    		// trigger computeScroll
    		invalidate();
    	}
    
    	/**
    	 * 更新footer
    	 * @param delta d
    	 */
    	private void updateFooterHeight(float delta) {
    		int height = mFooterView.getBottomMargin() + (int) delta;
    		if (mEnablePullLoad && !mPullLoading) {
    			// 如果footer的margin + 手指拖动的距离 > 限定的距离, 认为触发了上拉加载事件
    			if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load
    													// more.
    				mFooterView.setState(XListViewFooter.STATE_READY);
    			} else {
    				mFooterView.setState(XListViewFooter.STATE_NORMAL);
    			}
    		}
    		// 更新footer的margin值
    		mFooterView.setBottomMargin(height);
    
    //		setSelection(mTotalItemCount - 1); // scroll to bottom
    	}
    
    	/**
    	 * 重置footer的margin
    	 * 利用mScroller滚动 (从 bottomMargin 到 -bottomMargin)
    	 */
    	private void resetFooterHeight() {
    		int bottomMargin = mFooterView.getBottomMargin();
    		if (bottomMargin > 0) {
    			mScrollBack = SCROLLBACK_FOOTER;
    			mScroller.startScroll(0, bottomMargin, 0, -bottomMargin,
    					SCROLL_DURATION);
    			invalidate();
    		}
    	}
    
    	/**
    	 * 触发上拉加载更多事件,更新footer状态,触发回调
    	 */
    	private void startLoadMore() {
    		mPullLoading = true;
    		mFooterView.setState(XListViewFooter.STATE_LOADING);
    		if (mListViewListener != null) {
    			mListViewListener.onLoadMore();
    		}
    	}
    
    	@Override
    	public boolean onTouchEvent(MotionEvent ev) {
    		if (mLastY == -1) {
    			mLastY = ev.getRawY();
    		}
    
    		switch (ev.getAction()) {
    		case MotionEvent.ACTION_DOWN:
    			mLastY = ev.getRawY();
    			break;
    		case MotionEvent.ACTION_MOVE:
    			final float deltaY = ev.getRawY() - mLastY;
    			mLastY = ev.getRawY();
    
    			/**
    			 * ListView的第一个item在最顶部,并且手指向下拖动:更新header,触发header滑动监听(onXScrolling)
    			 * ListView的最后一个item在底部,并且手指向上拖动:更新footer
    			 *
    			 */
    			if (getFirstVisiblePosition() == 0
    					&& (mHeaderView.getVisibleHeight() > 0 || deltaY > 0)) {
    				// the first item is showing, header has shown or pull down.
    				updateHeaderHeight(deltaY / OFFSET_RADIO);
    				invokeOnScrolling();
    			} else if (getLastVisiblePosition() == mTotalItemCount - 1
    					&& (mFooterView.getBottomMargin() > 0 || deltaY < 0)) {
    				// last item, already pulled up or want to pull up.
    				updateFooterHeight(-deltaY / OFFSET_RADIO);
    			}
    			break;
    		default:
    			/**
    			 * 这里的ev.getAction()应该是:
    			 * UP 和 CANCEL
     			 */
    			mLastY = -1; // reset
    			if (getFirstVisiblePosition() == 0) {
    				// invoke refresh
    				/**
    				 * 释放手指的之后,header的高度 > 最原本的高度,触发下拉刷新事件
    				 * 更新状态,并回调
    				 * 最后重置高度
    				 */
    				if (mEnablePullRefresh
    						&& mHeaderView.getVisibleHeight() > mHeaderViewHeight) {
    					mPullRefreshing = true;
    					mHeaderView.setState(XListViewHeader.STATE_REFRESHING);
    					if (mListViewListener != null) {
    						mListViewListener.onRefresh();
    					}
    				}
    				resetHeaderHeight();
    			} else if (getLastVisiblePosition() == mTotalItemCount - 1) {
    				// invoke load more.
    				/**
    				 * 释放手指之后,footer的margin > 限定的距离
    				 * 触发上拉加载事件,并回调
    				 * 最后重置高度
    				 */
    				if (mEnablePullLoad
    				    && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA
    				    && !mPullLoading) {
    					startLoadMore();
    				}
    				resetFooterHeight();
    			}
    			break;
    		}
    		return super.onTouchEvent(ev);
    	}
    
    	/**
    	 * mScroll 实现滚动必须要覆盖的方法
    	 */
    	@Override
    	public void computeScroll() {
    		if (mScroller.computeScrollOffset()) {
    			if (mScrollBack == SCROLLBACK_HEADER) {
    				mHeaderView.setVisibleHeight(mScroller.getCurrY());
    			} else {
    				mFooterView.setBottomMargin(mScroller.getCurrY());
    			}
    			postInvalidate();
    			invokeOnScrolling();
    		}
    		super.computeScroll();
    	}
    
    	@Override
    	public void setOnScrollListener(OnScrollListener l) {
    		mScrollListener = l;
    	}
    
    	@Override
    	public void onScrollStateChanged(AbsListView view, int scrollState) {
    		if (mScrollListener != null) {
    			mScrollListener.onScrollStateChanged(view, scrollState);
    		}
    	}
    
    	@Override
    	public void onScroll(AbsListView view, int firstVisibleItem,
    			int visibleItemCount, int totalItemCount) {
    		// send to user's listener
    		mTotalItemCount = totalItemCount;
    		if (mScrollListener != null) {
    			mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
    					totalItemCount);
    		}
    	}
    
    	public void setXListViewListener(IXListViewListener l) {
    		mListViewListener = l;
    	}
    
    	/**
    	 * you can listen ListView.OnScrollListener or this one. it will invoke
    	 * onXScrolling when header/footer scroll back.
    	 */
    	public interface OnXScrollListener extends OnScrollListener {
    		public void onXScrolling(View view);
    	}
    
    	/**
    	 * implements this interface to get refresh/load more event.
    	 */
    	public interface IXListViewListener {
    		public void onRefresh();
    
    		public void onLoadMore();
    	}
    }
    

      

    结束,很简单啊。

  • 相关阅读:
    poj 3243 Clever Y(BabyStep GiantStep)
    poj 2417 Discrete Logging
    poj 3481 Double Queue
    hdu 4046 Panda
    hdu 2896 病毒侵袭
    poj 1442 Black Box
    hdu 2815 Mod Tree
    hdu 3065 病毒侵袭持续中
    hdu 1576 A/B
    所有控件
  • 原文地址:https://www.cnblogs.com/aprz512/p/4842143.html
Copyright © 2011-2022 走看看