Maxwin-z/XListView-Android (pull and refresh) source code parsing (2)
This article mainly posts the xlistview source code and a use instance, without too much explanation
Use instance, MainActivity
public class MainActivity extends Activity {private LinkedList
listItems = null; private XListView listView = null; private ArrayAdapter
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() {@Overridepublic void onRefresh() {new GetDataTask(true).execute();}@Overridepublic void onLoadMore() {new GetDataTask(false).execute();}}); listItems = new LinkedList
(); listItems.addAll(Arrays.asList(mStrings)); adapter = new ArrayAdapter
(this, android.R.layout.simple_list_item_1, listItems); listView.setAdapter(adapter); listView.setPullLoadEnable(true); } private class GetDataTask extends AsyncTask
{ 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/*** is used for the drop-down, slide and return */private Scroller; // used for scroll backprivate OnScrollListener mScrollListener; // user's scroll listener // the interface to trigger refresh and load more. private IXListViewListener mListViewListener;/*** drop-down header */private XListViewHeader mHeaderView;/*** drop-down Header Body, used to calculate the height of the header * hidden */private RelativeLayout mHeaderViewContent when refreshing is not allowed;/*** drop-down arrow */private TextView mHeaderTimeView; /*** height of the drop-down header */private int mHeaderViewHeight;/*** whether to pull down and refresh */private boolean mEnablePullRefresh = true;/*** whether to refresh, false indicates refreshing */private boolean mPullRefreshing = false; // is refreashing. // -- footer viewprivate XListViewFooter mFooterView; private boolean mEnablePullLoad; private bo Olean 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;/*** returns the head slide */private final static int SCROLLBACK_HEADER = 0;/*** returns the footer slide */private final static int SCROLLBACK_FOOTER = 1; private final static int SCROLL_DURATION = 40 0; // scroll back durationprivate 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); initWi ThContext (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); // initialize the drop-down header m HeaderView = new XListViewHeader (context); mHeaderViewContent = (RelativeLayout) mHeaderView. findViewById (R. id. xlistview_header_content); mHeaderTimeView = (TextView) mHeaderView. findViewById (R. id. xlistview_header_time); addHeaderView (mHeaderView); // initialize the mFooterView at the bottom = new XListViewFooter (context); // initialize the mHeaderView at the bottom. getViewTreeObserver (). addOnGlobalLayoutListener (new OnGlobalLayoutListener () {@ Over Ridepublic void onGlobalLayout () {mHeaderViewHeight = mHeaderViewContent. getHeight (); // get the height of the drop-down header getViewTreeObserver (). removeGlobalOnLayoutListener (this) ;}}) ;}@ Overridepublic void setAdapter (ListAdapter adapter) {/** add more footer to the bottom of the listview by pulling it up and adding it only once */if (mIsFooterReady = false) {mIsFooterReady = true; addFooterView (mFooterView ); // listview native method} super. setAdapter (adapter);}/*** set whether the pull-down refresh function is enabled *@ Param enable */public void setPullRefreshEnable (boolean enable) {mEnablePullRefresh = enable; if (! MEnablePullRefresh) {// disable this function to hide the header mHeaderViewContent. setVisibility (View. INVISIBLE);} else {mHeaderViewContent. setVisibility (View. VISIBLE);}/*** set whether to enable the pull-on function. * If You Want To enable the function, you must actively call this function * @ param enable */public void setPullLoadEnable (boolean enable) {mEnablePullLoad = enable; if (! MEnablePullLoad) {// If mFooterView is not enabled. hide (); // hide footermFooterView. setOnClickListener (null ); // cancel listening // make sure pull up don't show a line in bottom when listview with one page // ensure that the split line between items in listview disappears (the last one) setFooterDividersEnabled (false); // listview native method} 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 () {@ Overridepublic void onClick (View v) {startLoadMore () ;}}}/ *** stop refresh, reset header view. * stop refreshing, reset the header */public void stopRefresh () {if (mPullRefreshing = true) {mPullRefreshing = false; resetHeaderHeight () ;}/ *** stop load more, reset Footer view. * Stop loading more. Reset footer */public void stopLoadMore () {if (mPullLoading = true) {mPullLoading = false; mFooterView. setState (XListViewFooter. STATE_NORMAL) ;}}/*** set last refresh time * sets the 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) ;}/ *** update the header height * this function is used to record the number of dropped entries * @ param delta */private void updateHeaderHeight (float delta) {mHeaderView. setVisiableHeight (int) delta + mHeaderView. getVisiableHeight (); if (mEnablePullRefresh &&! MPullRefreshing) {// not refreshed, update the arrow if (mHeaderView. getVisiableHeight ()> mHeaderViewHeight) {mHeaderView. setState (XListViewHeader. STATE_READY);} else {mHeaderView. setState (XListViewHeader. STATE_NORMAL) ;}/// slip to the header setSelection (0); // scroll to top each time}/*** reset header view's height. * reset the header height */private void resetHeaderHeight () {int height = mHeaderView. getVisiableHeight (); if (height = 0) // not v Isible. return; // refreshing and header isn' t shown fully. do nothing. // if (mPullRefreshing & height <= mHeaderViewHeight) {return ;} int finalHeight = 0; // The default final height is returned, that is to say, the header should be removed // is refreshing, just scroll back to show all the header. // refreshing. if (mPullRefreshing & height> mHeaderViewHeight) {finalHeight = mHeaderViewHeight;} mScrollBack = SCROLLBACK_HEADER; // from the current position, returns to the hidden m in the header. Scroller. startScroll (0, height, 0, finalHeight-height, SCROLL_DURATION); // trigger computeScrollinvalidate ();} /*** update the distance between footer and the bottom * @ 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. mFooterView. setState (XListViewFooter. STATE_READY);} else {mFooterView. setState (XListViewFooter. STATE_NORMAL) ;}} mFooterView. setBottomMargin (height); // setSelection (mTotalItemCount-1); // scroll to bottom}/*** reset footer position */private void resetFooterHeight () {int bottomMargin = mFooterView. getBottomMarg In (); 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 () ;}@ Overridepublic boolean onTouchEvent (MotionEvent ev) {if (mLastY =-1) {// obtain the y coordinate of the touch, mLastY = ev. getRawY ();} switch (ev. getAction () {case MotionEvent. ACTION_DOWN: mLastY = ev. getRawY (); break; case MotionEvent. ACTION_MOVE: final float deltaY = ev. getRawY ()-mLastY; // pull down or pull up the number of offsetmLastY = ev. getRawY (); if (getFirstVisiblePosition () = 0 & (mHeaderView. getVisiab LeHeight ()> 0 | deltaY> 0) {// The first item is visible and displayed in the header or in the drop-down menu, 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) {// The last item is visible and footer is displayed or pulled up, indicates that the instance is in the uppull refresh status // last item, already pulled up or want to pull up. up DateFooterHeight (-deltaY/OFFSET_RADIO);} break; default: // action_upmLastY =-1; // resetif (getFirstVisiblePosition () = 0) {// invoke refreshif (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) ;}@ Overridepublic void computeScroll () {if (mScroller. computescroloffset () {if (mScrollBack = SCROLLBACK_HEADER) {mHeaderView. setVisiableHeight (mScroller. getCurrY ();} else {mFooterView. setBottomMargin (mScroller. getCurrY ();} postInvalidate (); invokeOnScrolling ();} super. computeScroll () ;}@ Overridepublic void se TOnScrollListener (OnScrollListener l) {mScrollListener = l ;}@ Overridepublic void onScrollStateChanged (AbsListView view, int scrollState) {if (mScrollListener! = Null) {mScrollListener. onScrollStateChanged (view, scrollState) ;}@ Overridepublic void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {// send to user's quota = 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. * drop-down and pull-up listeners */public interface IXListViewListener {public void onRefresh (); public void onLoadMore ();}}
XListViewHeader
Public class XListViewHeader extends LinearLayout {/*** drop-down layout subject */private LinearLayout mContainer;/*** drop-down arrow */private ImageView mArrowImageView; /*** ring progress bar */private ProgressBar mProgressBar;/*** text */private TextView mHintTextView; private int mState = STATE_NORMAL; private Animation mRotateUpAnim; private Animation mRotateDownAnim; /*** animation time */private final int ROTATE_ANIM_DURATION = 180; public Final static int STATE_NORMAL = 0; // public final static int STATE_READY = 1; // You can refresh public final static int STATE_REFRESHING = 2 from the drop-down list; // loading 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) {// initial information Set the height of the drop-down refresh view to 0LinearLayout. 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); // rotate the Animation mRotateUpAnim = new RotateAnimation (0.0f,-180.0f, Animation. RELATIVE_TO_SELF, 0.5f, Animation. RELATIVE_TO_SELF, 0.5f); // sets the animation time to mRotateUpAnim. setDuration (ROTATE_ANIM_DURATION); // when the animation ends, it stays at the last frame, that is, retaining the state of mRotateUpAnim after the animation. setFillAfter (true); // rotation Animation mRotateDownAnim = new RotateAnimation (-180.0f, 0.0f, Animation. RELATIVE_TO_SEL F, 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) {// display progress mArrowImageView. clearAnimation (); mArrowImageView. setVisibility (View. INVISIBLE); mProgressBar. setVisibility (View. VISIBLE);} else {// display the arrow picture 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;}/*** sets the effective height of the drop-down header * @ 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);}/*** get the effective height of the drop-down header * @ 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; // You can refresh public final static int STATE_LOADING = 2; // loading 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 );} /*** set status ** @ 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) ;}}/*** set the bottom height of 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);}/*** get the bottom height of 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);}/*** initialize Layout * @ 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 );}}