当前位置: 代码迷 >> Android >> Maxwin-z/XListView-Android(下拉刷新上拉加载)源码解析(2)
  详细解决方案

Maxwin-z/XListView-Android(下拉刷新上拉加载)源码解析(2)

热度:82   发布时间:2016-04-28 00:47:15.0
Maxwin-z/XListView-Android(下拉刷新上拉加载)源码解析(二)

转载请注明出处http://blog.csdn.net/crazy__chen/article/details/45980399

源文件下载地址http://download.csdn.net/detail/kangaroo835127729/8736887

本文主要是贴出xlistview的源代码和一个使用实例,没有过多讲解

使用实例,MainActivity

public class MainActivity extends Activity {			private LinkedList<String>   listItems = null;    	private XListView     listView  = null;    private ArrayAdapter<String> adapter;     private String[]             mStrings  = { "Aaaaaa", "Bbbbbb", "Cccccc", "Dddddd", "Eeeeee",            "Ffffff", "Gggggg", "Hhhhhh", "Iiiiii", "Jjjjjj", "Kkkkkk", "Llllll", "Mmmmmm",            "Nnnnnn",                     };     @Override    public void onCreate(Bundle savedInstanceState) {    	super.onCreate(savedInstanceState);    	setContentView(R.layout.activity_main);                      listView = (XListView)findViewById(R.id.mlist);        listView.setXListViewListener(new IXListViewListener() {						@Override			public void onRefresh() {				new GetDataTask(true).execute();							}						@Override			public void onLoadMore() {				new GetDataTask(false).execute();							}		});               listItems = new LinkedList<String>();        listItems.addAll(Arrays.asList(mStrings));        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, listItems);        listView.setAdapter(adapter);        listView.setPullLoadEnable(true);    }     private class GetDataTask extends AsyncTask<Void, Void, String[]> {         private boolean isDropDown;         public GetDataTask(boolean isDropDown){            this.isDropDown = isDropDown;        }         @Override        protected String[] doInBackground(Void... params) {            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                ;            }            return mStrings;        }         @Override        protected void onPostExecute(String[] result) {             if (isDropDown) {                listItems.addFirst("Added after drop down");                adapter.notifyDataSetChanged();                                                    listView.stopRefresh();            } else {                listItems.add("Added after on bottom");                adapter.notifyDataSetChanged();                listView.stopLoadMore();                          }             super.onPostExecute(result);        }    }}

XListView

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;	/**	 * 下拉头部	 */	private XListViewHeader mHeaderView;		/**	 * 下拉头主体,用于计算头部的高度	 * 当不能刷新时,被隐藏	 */	private RelativeLayout mHeaderViewContent;	/**	 * 下拉箭头	 */	private TextView mHeaderTimeView;	/**	 * 下拉头部的高度	 */	private int mHeaderViewHeight;	/**	 * 能否下拉刷新	 */	private boolean mEnablePullRefresh = true;	/**	 * 是否正在刷新,false表示正在刷新	 */	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;	/**	 * footer滑动返回	 */	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.	/**	 * @param context	 */	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);	}	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);		//初始化下拉头		mHeaderView = new XListViewHeader(context);		mHeaderViewContent = (RelativeLayout) mHeaderView				.findViewById(R.id.xlistview_header_content);		mHeaderTimeView = (TextView) mHeaderView				.findViewById(R.id.xlistview_header_time);		addHeaderView(mHeaderView);		//初始化底部		mFooterView = new XListViewFooter(context);		//初始化下拉头高度		mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(				new OnGlobalLayoutListener() {					@Override					public void onGlobalLayout() {						mHeaderViewHeight = mHeaderViewContent.getHeight();//获得下拉头的高度						getViewTreeObserver()								.removeGlobalOnLayoutListener(this);					}				});	}	@Override	public void setAdapter(ListAdapter adapter) {		/*		 * 将上拉加载更多footer加入listview的底部		 * 并且保证只加入一次		 */		if (mIsFooterReady == false) {			mIsFooterReady = true;			addFooterView(mFooterView);//listview原生方法		}		super.setAdapter(adapter);	}	/**	 	 * 设置下拉刷新功能是否开启	 * @param enable	 */	public void setPullRefreshEnable(boolean enable) {		mEnablePullRefresh = enable;		if (!mEnablePullRefresh) {//不开启,隐藏头部			mHeaderViewContent.setVisibility(View.INVISIBLE);		} else {			mHeaderViewContent.setVisibility(View.VISIBLE);		}	}	/**	 * 设置上拉加载更多功能是否开启	 * 如果要开启,必须主动调用这个函数	 	 * @param enable	 */	public void setPullLoadEnable(boolean enable) {		mEnablePullLoad = enable;		if (!mEnablePullLoad) {//如果不开启			mFooterView.hide();//隐藏footer			mFooterView.setOnClickListener(null);//取消监听			//make sure "pull up" don't show a line in bottom when listview with one page 			//保证listview的item之间的分割线消失(最后一条)			setFooterDividersEnabled(false);//listview原生方法		} 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();				}			});		}	}	/**	 * stop refresh, reset header view.	 * 停止刷新,重置头部	 */	public void stopRefresh() {		if (mPullRefreshing == true) {			mPullRefreshing = false;			resetHeaderHeight();		}	}	/**	 * stop load more, reset footer view.	 * 停止加载更多,重置footer	 */	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);	}	private void invokeOnScrolling() {		if (mScrollListener instanceof OnXScrollListener) {			OnXScrollListener l = (OnXScrollListener) mScrollListener;			l.onXScrolling(this);		}	}	/**	 * 更新头部高度	 * 这个函数用于下拉时,记录下拉了多少	 * @param delta	 */	private void updateHeaderHeight(float delta) {		mHeaderView.setVisiableHeight((int) delta				+ mHeaderView.getVisiableHeight());		if (mEnablePullRefresh && !mPullRefreshing) {//未处于刷新状态,更新箭头			if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {				mHeaderView.setState(XListViewHeader.STATE_READY);			} else {				mHeaderView.setState(XListViewHeader.STATE_NORMAL);			}		}				//滑动到头部		setSelection(0); // scroll to top each time	}	/**	 * reset header view's height.	 * 重置头部高度	 */	private void resetHeaderHeight() {		int height = mHeaderView.getVisiableHeight();		if (height == 0) // not visible.			return;		// refreshing and header isn't shown fully. do nothing.		//正在刷新,或者头部没有完全显示,返回		if (mPullRefreshing && height <= mHeaderViewHeight) {			return;		}		int finalHeight = 0; // 默认最终高度,也就是说要让头部消失		// 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	 */	private void updateFooterHeight(float delta) {		int height = mFooterView.getBottomMargin() + (int) delta;		if (mEnablePullLoad && !mPullLoading) {			if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load上拉足够高才去加载													// more.				mFooterView.setState(XListViewFooter.STATE_READY);			} else {				mFooterView.setState(XListViewFooter.STATE_NORMAL);			}		}		mFooterView.setBottomMargin(height);//		setSelection(mTotalItemCount - 1); // scroll to bottom	}		/**	 * 重置footer位置	 */	private void resetFooterHeight() {		int bottomMargin = mFooterView.getBottomMargin();		if (bottomMargin > 0) {			mScrollBack = SCROLLBACK_FOOTER;			mScroller.startScroll(0, bottomMargin, 0, -bottomMargin,					SCROLL_DURATION);			invalidate();		}	}	private void startLoadMore() {		mPullLoading = true;		mFooterView.setState(XListViewFooter.STATE_LOADING);		if (mListViewListener != null) {			mListViewListener.onLoadMore();		}	}	@Override	public boolean onTouchEvent(MotionEvent ev) {		if (mLastY == -1) {//获得触摸时的y坐标			mLastY = ev.getRawY();		}		switch (ev.getAction()) {		case MotionEvent.ACTION_DOWN:			mLastY = ev.getRawY();			break;		case MotionEvent.ACTION_MOVE:			final float deltaY = ev.getRawY() - mLastY;//下拉或者上拉了多少offset			mLastY = ev.getRawY();			if (getFirstVisiblePosition() == 0					&& (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {//第一个item可见并且头部部分显示或者下拉操作,则表示处于下拉刷新状态				// 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)) {//最后一个item可见并且footer被上拉显示或者上拉操作,则表示处于上拉刷新状态				// last item, already pulled up or want to pull up.				updateFooterHeight(-deltaY / OFFSET_RADIO);			}			break;		default://action_up						mLastY = -1; // reset			if (getFirstVisiblePosition() == 0) {				// invoke refresh				if (mEnablePullRefresh						&& mHeaderView.getVisiableHeight() > mHeaderViewHeight) {					mPullRefreshing = true;					mHeaderView.setState(XListViewHeader.STATE_REFRESHING);					if (mListViewListener != null) {						mListViewListener.onRefresh();					}				}				resetHeaderHeight();			} else if (getLastVisiblePosition() == mTotalItemCount - 1) {				// invoke load more.				if (mEnablePullLoad				    && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA				    && !mPullLoading) {					startLoadMore();				}				resetFooterHeight();			}			break;					}		return super.onTouchEvent(ev);	}	@Override	public void computeScroll() {		if (mScroller.computeScrollOffset()) {			if (mScrollBack == SCROLLBACK_HEADER) {				mHeaderView.setVisiableHeight(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();	}}

XListViewHeader

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	 * @param attrs	 */	public XListViewHeader(Context context, AttributeSet attrs) {		super(context, attrs);		initView(context);	}	private void initView(Context context) {		// 初始情况,设置下拉刷新view高度为0		LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(				LayoutParams.FILL_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);	}	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:			if (mState == STATE_READY) {				mArrowImageView.startAnimation(mRotateDownAnim);			}			if (mState == STATE_REFRESHING) {				mArrowImageView.clearAnimation();			}			mHintTextView.setText(R.string.xlistview_header_hint_normal);			break;		case 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	 */	public void setVisiableHeight(int height) {		if (height < 0)			height = 0;		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer				.getLayoutParams();		lp.height = height;		mContainer.setLayoutParams(lp);	}	/**	 * 获得下拉头有效高度	 * @return	 */	public int getVisiableHeight() {		return mContainer.getLayoutParams().height;	}}

XListViewFooter
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	 */	public void setState(int state) {		mHintView.setVisibility(View.INVISIBLE);		mProgressBar.setVisibility(View.INVISIBLE);		mHintView.setVisibility(View.INVISIBLE);		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里底部的高度	 * @param height	 */	public void setBottomMargin(int height) {		if (height < 0) return ;		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();		lp.bottomMargin = height;		mContentView.setLayoutParams(lp);	}		/**	 * 获得footer里底部的高度	 * @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);	}		/**	 * hide footer when disable pull load more	 */	public void hide() {		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();		lp.height = 0;		mContentView.setLayoutParams(lp);	}		/**	 * show footer	 */	public void show() {		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();		lp.height = LayoutParams.WRAP_CONTENT;		mContentView.setLayoutParams(lp);	}		/**	 * 初始化布局	 * @param context	 */	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.FILL_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);	}		}

  相关解决方案