博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
android xlistview
阅读量:6457 次
发布时间:2019-06-23

本文共 42159 字,大约阅读时间需要 140 分钟。

 

 

main.xml

 

 

xlistview_header.xml

 

 

 

xlistview_footer.xml

 

 

message_header.xml

 

 

package com.curiousby.demoxlistview;import java.util.ArrayList;import java.util.List;import com.curiousby.demoxlistview.xlistview.MsgListView; import com.curiousby.demoxlistview.xlistview.MsgListView.IXListViewListener;import android.os.Bundle;import android.view.MotionEvent;import android.view.View;import android.view.View.OnTouchListener;import android.app.Activity;import android.content.Context; public class MainActivity extends Activity implements IXListViewListener, OnTouchListener {	private List
mlist = new ArrayList
(); private MylistAdapter mAdapter; private Context context; private MsgListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); context = MainActivity.this; mAdapter = new MylistAdapter( this); mAdapter.setMlist(mlist); listView = (MsgListView) findViewById(R.id.mylist); listView.setOnTouchListener(this); listView.setPullLoadEnable(false); listView.setXListViewListener(this); listView.setAdapter(mAdapter); listView.setSelection(mAdapter.getCount() - 1); mlist.add("a"); mAdapter.notifyDataSetChanged(); } private int i; @Override public void onRefresh() { mlist.add(""+i++); mAdapter.notifyDataSetChanged(); listView.setSelection(mAdapter.getCount() - 1); listView.stopRefresh(); } @Override public void onLoadMore() { mlist.add(""+i++); listView.setSelection(mAdapter.getCount() - 1); mAdapter.notifyDataSetChanged(); } @Override public boolean onTouch(View arg0, MotionEvent arg1) { return false; } }

 

 

 

package com.curiousby.demoxlistview;import java.util.List;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;public class MylistAdapter extends BaseAdapter{	private List
mlist; private LayoutInflater mInflater; private Context context; public MylistAdapter( Context context) { this.mInflater = LayoutInflater.from(context); this.context = context; } public void setMlist(List
mlist) { this.mlist = mlist; notifyDataSetChanged(); } @Override public int getCount() { if (mlist != null ) { return mlist.size(); } return 0; } @Override public String getItem(int position) { if (mlist != null ) { return (String) mlist.get(position); } return ""; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { String item = getItem(position); ViewHolder viewHolder = null; if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item, parent, false); viewHolder =new ViewHolder(convertView); convertView.setTag(viewHolder); }else{ viewHolder = (ViewHolder) convertView.getTag( ); } viewHolder.text.setText(item); return convertView; } class ViewHolder { private TextView text; ViewHolder(View baseView){ this.text = (TextView) baseView.findViewById(R.id.text); } }}

 

 

/** * @file XListViewHeader.java * @create Apr 18, 2012 5:22:27 PM * @author Maxwin * @description XListView's header */package com.curiousby.demoxlistview.xlistview;import com.curiousby.demoxlistview.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	 * @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;	}	public void setVisiableHeight(int height) {		if (height < 0)			height = 0;		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer				.getLayoutParams();		lp.height = height;		mContainer.setLayoutParams(lp);	}	public int getVisiableHeight() {		return mContainer.getHeight();	}}

 

 

/** * @file XFooterView.java * @create Mar 31, 2012 9:33:43 PM * @author Maxwin * @description XListView's footer */package com.curiousby.demoxlistview.xlistview;import com.curiousby.demoxlistview.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; 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);	}		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);		}	}		public void setBottomMargin(int height) {		if (height < 0) return ;		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)mContentView.getLayoutParams();		lp.bottomMargin = height;		mContentView.setLayoutParams(lp);	}		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);	}		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);	}		}

 

 

/** * @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 com.curiousby.demoxlistview.xlistview; import com.curiousby.demoxlistview.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.ExpandableListView;import android.widget.ListAdapter;import android.widget.RelativeLayout;import android.widget.Scroller;import android.widget.TextView; public class XExpandableListView extends ExpandableListView 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.	/**	 * @param context	 */	public XExpandableListView(Context context) {		super(context);		initWithContext(context);	}	public XExpandableListView(Context context, AttributeSet attrs) {		super(context, attrs);		initWithContext(context);	}	public XExpandableListView(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);		// 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);					}				});	}	@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	 */	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	 */	public void setPullLoadEnable(boolean enable) {		mEnablePullLoad = enable;		if (!mEnablePullLoad) {			mFooterView.hide();			mFooterView.setOnClickListener(null);		} else {			mPullLoading = false;			mFooterView.show();			mFooterView.setState(XListViewFooter.STATE_NORMAL);			// 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.	 */	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);	}	public void setRefreshTime(long time) {		mHeaderTimeView.setText(TimeUtil.getChatTime(time));	}	private void invokeOnScrolling() {		if (mScrollListener instanceof OnXScrollListener) {			OnXScrollListener l = (OnXScrollListener) mScrollListener;			l.onXScrolling(this);		}	}	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; // 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();	}	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	}	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) {			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();			if (getFirstVisiblePosition() == 0					&& (mHeaderView.getVisiableHeight() > 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:			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) {					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();	}}

 

 

 

package com.curiousby.demoxlistview.xlistview;import java.text.SimpleDateFormat;import java.util.Date;import android.annotation.SuppressLint;/** * 时间工具类 *  * @author way *  */@SuppressLint("SimpleDateFormat")public class TimeUtil {	public static String getTime(long time) {		SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd HH:mm");		return format.format(new Date(time));	}	public static String getHourAndMin(long time) {		SimpleDateFormat format = new SimpleDateFormat("HH:mm");		return format.format(new Date(time));	}	public static String getChatTime(long timesamp) {		String result = "";		SimpleDateFormat sdf = new SimpleDateFormat("dd");		Date today = new Date(System.currentTimeMillis());		Date otherDay = new Date(timesamp);		int temp = Integer.parseInt(sdf.format(today))				- Integer.parseInt(sdf.format(otherDay));		switch (temp) {		case 0:			result = "今天 " + getHourAndMin(timesamp);			break;		case 1:			result = "昨天 " + getHourAndMin(timesamp);			break;		case 2:			result = "前天 " + getHourAndMin(timesamp);			break;		default:			// result = temp + "天前 ";			result = getTime(timesamp);			break;		}		return result;	}}

 

 

/** * @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 com.curiousby.demoxlistview.xlistview;import com.curiousby.demoxlistview.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; //com.curiousby.demoxlistview.xlistview.MsgListViewpublic class MsgListView 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 MsgHeader 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.	/**	 * @param context	 */	public MsgListView(Context context) {		super(context);		initWithContext(context);	}	public MsgListView(Context context, AttributeSet attrs) {		super(context, attrs);		initWithContext(context);	}	public MsgListView(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);		// init header view		mHeaderView = new MsgHeader(context);		mHeaderViewContent = (RelativeLayout) mHeaderView				.findViewById(R.id.msg_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);					}				});	}	@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	 */	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	 */	public void setPullLoadEnable(boolean enable) {		mEnablePullLoad = enable;		if (!mEnablePullLoad) {			mFooterView.hide();			mFooterView.setOnClickListener(null);		} else {			mPullLoading = false;			mFooterView.show();			mFooterView.setState(XListViewFooter.STATE_NORMAL);			// 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.	 */	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);	// }	//	// public void setRefreshTime(long time) {	// mHeaderTimeView.setText(TimeUtil.getChatTime(time));	// }	private void invokeOnScrolling() {		if (mScrollListener instanceof OnXScrollListener) {			OnXScrollListener l = (OnXScrollListener) mScrollListener;			l.onXScrolling(this);		}	}	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; // 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();	}	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	}	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) {			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();			if (getFirstVisiblePosition() == 0					&& (mHeaderView.getVisiableHeight() > 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:			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) {					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();	}}

 

 

/** * @file XListViewHeader.java * @create Apr 18, 2012 5:22:27 PM * @author Maxwin * @description XListView's header */package com.curiousby.demoxlistview.xlistview;import com.curiousby.demoxlistview.R;import android.content.Context;import android.util.AttributeSet;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.widget.LinearLayout;import android.widget.ProgressBar;import android.widget.TextView; public class MsgHeader extends LinearLayout {	private LinearLayout mContainer;	private ProgressBar mProgressBar;	private TextView mHintTextView;	private int mState = STATE_NORMAL;	public final static int STATE_NORMAL = 0;	public final static int STATE_READY = 1;	public final static int STATE_REFRESHING = 2;	public MsgHeader(Context context) {		super(context);		initView(context);	}	/**	 * @param context	 * @param attrs	 */	public MsgHeader(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.message_header, null);		addView(mContainer, lp);		setGravity(Gravity.BOTTOM);		mHintTextView = (TextView) findViewById(R.id.xlistview_header_hint_textview);		mProgressBar = (ProgressBar) findViewById(R.id.xlistview_header_progressbar);	}	public void setState(int state) {		if (state == mState)			return;		if (state == STATE_REFRESHING) { // 显示进度			mProgressBar.setVisibility(View.VISIBLE);		} else { // 显示箭头图片			mProgressBar.setVisibility(View.INVISIBLE);		}		switch (state) {		case STATE_NORMAL:			if (mState == STATE_READY) {			}			if (mState == STATE_REFRESHING) {			}			mHintTextView.setVisibility(View.VISIBLE);			mHintTextView.setText("显示更多消息");			break;		case STATE_READY:			if (mState != STATE_READY) {				mHintTextView.setVisibility(View.VISIBLE);				mHintTextView.setText("释放即可显示");			}			break;		case STATE_REFRESHING:			// mHintTextView.setText(R.string.xlistview_header_hint_loading);			mHintTextView.setVisibility(View.GONE);			break;		default:		}		mState = state;	}	public void setVisiableHeight(int height) {		if (height < 0)			height = 0;		LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mContainer				.getLayoutParams();		lp.height = height;		mContainer.setLayoutParams(lp);	}	public int getVisiableHeight() {		return mContainer.getHeight();	}}

 

 

 

package com.curiousby.demoxlistview.xlistview;import android.content.Context;import android.graphics.Canvas;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.AbsListView;import android.widget.AbsListView.OnScrollListener;import android.widget.ExpandableListAdapter;import android.widget.ExpandableListView;import android.widget.ExpandableListView.OnGroupClickListener;public class IphoneTreeView extends ExpandableListView implements		OnScrollListener, OnGroupClickListener {	public IphoneTreeView(Context context, AttributeSet attrs, int defStyle) {		super(context, attrs, defStyle);		registerListener();	}	public IphoneTreeView(Context context, AttributeSet attrs) {		super(context, attrs);		registerListener();	}	public IphoneTreeView(Context context) {		super(context);		registerListener();	}	/**	 * Adapter 接口 . 列表必须实现此接口 .	 */	public interface IphoneTreeHeaderAdapter {		public static final int PINNED_HEADER_GONE = 0;		public static final int PINNED_HEADER_VISIBLE = 1;		public static final int PINNED_HEADER_PUSHED_UP = 2;		/**		 * 获取 Header 的状态		 * 		 * @param groupPosition		 * @param childPosition		 * @return 		 *         PINNED_HEADER_GONE,PINNED_HEADER_VISIBLE,PINNED_HEADER_PUSHED_UP		 *         其中之一		 */		int getTreeHeaderState(int groupPosition, int childPosition);		/**		 * 配置 QQHeader, 让 QQHeader 知道显示的内容		 * 		 * @param header		 * @param groupPosition		 * @param childPosition		 * @param alpha		 */		void configureTreeHeader(View header, int groupPosition,				int childPosition, int alpha);		/**		 * 设置组按下的状态		 * 		 * @param groupPosition		 * @param status		 */		void onHeadViewClick(int groupPosition, int status);		/**		 * 获取组按下的状态		 * 		 * @param groupPosition		 * @return		 */		int getHeadViewClickStatus(int groupPosition);	}	private static final int MAX_ALPHA = 255;	private IphoneTreeHeaderAdapter mAdapter;	/**	 * 用于在列表头显示的 View,mHeaderViewVisible 为 true 才可见	 */	private View mHeaderView;	/**	 * 列表头是否可见	 */	private boolean mHeaderViewVisible;	private int mHeaderViewWidth;	private int mHeaderViewHeight;	public void setHeaderView(View view) {		mHeaderView = view;		AbsListView.LayoutParams lp = new AbsListView.LayoutParams(				ViewGroup.LayoutParams.MATCH_PARENT,				ViewGroup.LayoutParams.WRAP_CONTENT);		view.setLayoutParams(lp);		if (mHeaderView != null) {			setFadingEdgeLength(0);		}		requestLayout();	}	private void registerListener() {		setOnScrollListener(this);		setOnGroupClickListener(this);	}	/**	 * 点击 HeaderView 触发的事件	 */	private void headerViewClick() {		long packedPosition = getExpandableListPosition(this				.getFirstVisiblePosition());		int groupPosition = ExpandableListView				.getPackedPositionGroup(packedPosition);		if (mAdapter.getHeadViewClickStatus(groupPosition) == 1) {			this.collapseGroup(groupPosition);			mAdapter.onHeadViewClick(groupPosition, 0);		} else {			this.expandGroup(groupPosition);			mAdapter.onHeadViewClick(groupPosition, 1);		}		this.setSelectedGroup(groupPosition);	}	private float mDownX;	private float mDownY;	/**	 * 如果 HeaderView 是可见的 , 此函数用于判断是否点击了 HeaderView, 并对做相应的处理 , 因为 HeaderView	 * 是画上去的 , 所以设置事件监听是无效的 , 只有自行控制 .	 */	@Override	public boolean onTouchEvent(MotionEvent ev) {		if (mHeaderViewVisible) {			switch (ev.getAction()) {			case MotionEvent.ACTION_DOWN:				mDownX = ev.getX();				mDownY = ev.getY();				if (mDownX <= mHeaderViewWidth && mDownY <= mHeaderViewHeight) {					return true;				}				break;			case MotionEvent.ACTION_UP:				float x = ev.getX();				float y = ev.getY();				float offsetX = Math.abs(x - mDownX);				float offsetY = Math.abs(y - mDownY);				// 如果 HeaderView 是可见的 , 点击在 HeaderView 内 , 那么触				// 发 headerClick()				if (x <= mHeaderViewWidth && y <= mHeaderViewHeight						&& offsetX <= mHeaderViewWidth						&& offsetY <= mHeaderViewHeight) {					if (mHeaderView != null) {						headerViewClick();					}					return true;				}				break;			default:				break;			}		}		return super.onTouchEvent(ev);	}	@Override	public void setAdapter(ExpandableListAdapter adapter) {		super.setAdapter(adapter);		mAdapter = (IphoneTreeHeaderAdapter) adapter;	}	/**	 * 	 * 点击了 Group 触发的事件 , 要根据根据当前点击 Group 的状态来	 */	@Override	public boolean onGroupClick(ExpandableListView parent, View v,			int groupPosition, long id) {		if (mAdapter.getHeadViewClickStatus(groupPosition) == 0) {			mAdapter.onHeadViewClick(groupPosition, 1);			parent.expandGroup(groupPosition);			parent.setSelectedGroup(groupPosition);		} else if (mAdapter.getHeadViewClickStatus(groupPosition) == 1) {			mAdapter.onHeadViewClick(groupPosition, 0);			parent.collapseGroup(groupPosition);		}		// 返回 true 才可以弹回第一行 , 不知道为什么		return true;	}	@Override	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {		super.onMeasure(widthMeasureSpec, heightMeasureSpec);		if (mHeaderView != null) {			measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec);			mHeaderViewWidth = mHeaderView.getMeasuredWidth();			mHeaderViewHeight = mHeaderView.getMeasuredHeight();		}	}	private int mOldState = -1;	@Override	protected void onLayout(boolean changed, int left, int top, int right,			int bottom) {		super.onLayout(changed, left, top, right, bottom);		final long flatPostion = getExpandableListPosition(getFirstVisiblePosition());		final int groupPos = ExpandableListView				.getPackedPositionGroup(flatPostion);		final int childPos = ExpandableListView				.getPackedPositionChild(flatPostion);		int state = mAdapter.getTreeHeaderState(groupPos, childPos);		if (mHeaderView != null && mAdapter != null && state != mOldState) {			mOldState = state;			mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);		}		configureHeaderView(groupPos, childPos);	}	public void configureHeaderView(int groupPosition, int childPosition) {		if (mHeaderView == null || mAdapter == null				|| ((ExpandableListAdapter) mAdapter).getGroupCount() == 0) {			return;		}		int state = mAdapter.getTreeHeaderState(groupPosition, childPosition);		switch (state) {		case IphoneTreeHeaderAdapter.PINNED_HEADER_GONE: {			mHeaderViewVisible = false;			break;		}		case IphoneTreeHeaderAdapter.PINNED_HEADER_VISIBLE: {			mAdapter.configureTreeHeader(mHeaderView, groupPosition,					childPosition, MAX_ALPHA);			if (mHeaderView.getTop() != 0) {				mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight);			}			mHeaderViewVisible = true;			break;		}		case IphoneTreeHeaderAdapter.PINNED_HEADER_PUSHED_UP: {			View firstView = getChildAt(0);			int bottom = firstView.getBottom();			// intitemHeight = firstView.getHeight();			int headerHeight = mHeaderView.getHeight();			int y;			int alpha;			if (bottom < headerHeight) {				y = (bottom - headerHeight);				alpha = MAX_ALPHA * (headerHeight + y) / headerHeight;			} else {				y = 0;				alpha = MAX_ALPHA;			}			mAdapter.configureTreeHeader(mHeaderView, groupPosition,					childPosition, alpha);			if (mHeaderView.getTop() != y) {				mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight						+ y);			}			mHeaderViewVisible = true;			break;		}		}	}	@Override	/**	 * 列表界面更新时调用该方法(如滚动时)	 */	protected void dispatchDraw(Canvas canvas) {		super.dispatchDraw(canvas);		if (mHeaderViewVisible) {			// 分组栏是直接绘制到界面中,而不是加入到ViewGroup中			drawChild(canvas, mHeaderView, getDrawingTime());		}	}	@Override	public void onScroll(AbsListView view, int firstVisibleItem,			int visibleItemCount, int totalItemCount) {		final long flatPos = getExpandableListPosition(firstVisibleItem);		int groupPosition = ExpandableListView.getPackedPositionGroup(flatPos);		int childPosition = ExpandableListView.getPackedPositionChild(flatPos);		configureHeaderView(groupPosition, childPosition);	}	@Override	public void onScrollStateChanged(AbsListView view, int scrollState) {	}}

 

 

 

 

 

 

 

 

 

 

捐助开发者

在兴趣的驱动下,写一个免费的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(右上角的爱心标志,支持支付宝和PayPal捐助),没钱捧个人场,谢谢各位。

 
 
 谢谢您的赞助,我会做的更好!

 

 

 

转载地址:http://kmizo.baihongyu.com/

你可能感兴趣的文章
Java数据类型和MySql数据类型对应表
查看>>
面向对象编程(十)——继承之Super关键字及内存分析
查看>>
Atitit. Atiposter 发帖机 新特性 poster new feature v7 q39
查看>>
Android View 如何测量
查看>>
splay tree成段更新,成段查询poj3466
查看>>
Data Usage Technical Information
查看>>
java程序内存泄漏排查
查看>>
iOS开发之--NSPredicate
查看>>
UML进行Linux内核调试
查看>>
通过url链接登录其他系统
查看>>
补全aaz288 可能有问题的过程 P_COMPL_AAZ288
查看>>
ASP.NET 使用Ajax
查看>>
Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]
查看>>
maven scope含义的说明
查看>>
DS实验题 Searchname
查看>>
css样式表中的样式覆盖顺序(转)
查看>>
Jenkins管理静态资源
查看>>
一文读懂质量保证和质量控制
查看>>
【iCore4 双核心板_ARM】例程十八:USBD_VCP实验——虚拟串口
查看>>
如何创建带有.的文件夹
查看>>