Android-custom controls implement ListView pull-down refresh and androidlistview
This blog introduces you to a common feature of android-ListView pull-down refresh (refer to the blog of another user who forgot the website, read his code and understand the comments, hoping to help you ):
First, the mobile phone displays the following interface when the drop-down fails:
The following code is a custom Sample Control:
Package com. dhsr. smartID. view; 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; I Mport com. example. sirelinkscanapp. R;/*** custom control. When the drop-down is completed, the ListView displays "the icon and prompt is refreshing ......" * @ Author cyf **/public class XListViewHeader extends LinearLayout {private LinearLayout mContainer; // picture private ImageView mArrowImageView; // circular progress bar private ProgressBar mProgressBar; private TextView mHintTextView; // State private int mState = STATE_NORMAL; // Animation private Animation mRotateUpAnim; private Animation mRotateDownAnim; private final int ROTATE_ANIM_DURATION = 180; // normal public final static int STATE_NORMAL = 0; // prepare to refresh 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);}/*** "release to refresh ...... Refreshing ......" ** @ Param context */private void initView (Context context) {// in the Initial State, set the drop-down refresh view height to 0LinearLayout. layoutParams lp = new LinearLayout. layoutParams (LayoutParams. MATCH_PARENT, 0); mContainer = (LinearLayout) LayoutInflater. from (context ). inflate (R. layout. xlistview_header, null); // load the view addView (mContainer, lp); // setGravity (Gravity. BOTTOM); // initialization control mArrowImageView = (ImageView) findViewById (R. id. xlis Tview_header_arrow); mHintTextView = (TextView) findViewById (R. id. xlistview_header_hint_textview); mProgressBar = (ProgressBar) findViewById (R. id. xlistview_header_progressbar); // set the Animation 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);}/*** execute the corresponding function based on the drop-down status to start and stop the corresponding animation ** @ param state */public void setState (int state) {if (state = mState) return; if (state = STATE_REFRESHING) {// display progress mArrowImageView. clearAnimation (); mArrowImageView. setVisibility (Vi Ew. 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) {// start the animation mArrowImageView. startAnimation (mRotateDownAnim);} // refresh if (mState = STATE_REFRESHING) {// clear the animation mArrowImageView. clearAnimation ();} mHintTextView. setText (R. string. xlistview_h Eader_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 ();}}
Next, you need to customize your own ListView to inherit from the android ListView, so that you can easily add new methods.
Package com. dhsr. smartID. view; 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. wid Get. listView; import android. widget. relativeLayout; import android. widget. scroller; import android. widget. textView; import com. example. sirelinkscanapp. r;/*** custom ListView ** @ author cyf **/public class XListView extends ListView implements OnScrollListener {private final String TAG = "XListView "; private float mLastY =-1; private Scroller mscroler; // sliding private OnScrollListener mScrollListener; // outside Create a listener private IXListViewListener mListViewListener; // The custom control private XListViewHeader mHeaderView; private RelativeLayout mHeaderViewContent; private TextView mHeaderTimeView; private int mHeaderViewHeight; // header view's heightprivate boolean mEnablePullRefresh = true; private boolean mPullRefreshing = false; // is refreashing. private boolean mEnablePullLoad; private boolean mPullLoading; private boo Lean 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 durationprivate final static int PULL_LOAD_MOR E_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, AttributeS Et attrs, int defStyle) {super (context, attrs, defStyle); initWithContext (context );} /*** initialize the control ** @ param context */private void initWithContext (Context context) {mScroller = new Scroller (context, new DecelerateInterpolator (); super. setOnScrollListener (this); mHeaderView = new XListViewHeader (context); mHeaderViewContent = (RelativeLayout) mHeaderView. findViewById (R. id. xlistview_header_content); mHea DerTimeView = (TextView) mHeaderView. findViewById (R. id. xlistview_header_time); addHeaderView (mHeaderView, null, false); mHeaderView. getViewTreeObserver (). addOnGlobalLayoutListener (new OnGlobalLayoutListener () {@ Overridepublic void onGlobalLayout () {mHeaderViewHeight = mHeaderViewContent. getHeight (); getViewTreeObserver (). removeGlobalOnLayoutListener (this) ;}}) ;}@ Overridepublic void setAdapter (ListAdap Ter adapter) {// make sure XListViewFooter is the last footer view, and only add once. if (mIsFooterReady = false) {if (mEnablePullLoad) {mIsFooterReady = true; // addFooterView (mFooterView);} super. setAdapter (adapter);} public void setPullRefreshEnable (boolean enable) {mEnablePullRefresh = enable; if (! MEnablePullRefresh) {// disable, hide the contentmHeaderViewContent. setVisibility (View. INVISIBLE);} else {mHeaderViewContent. setVisibility (View. VISIBLE) ;}/ *** stop refreshing */public void stopRefresh () {if (mPullRefreshing = true) {mPullRefreshing = false; resetHeaderHeight ();}} // when you enter the Activity, execute a drop-down refresh public void startRefresh () {if (mPullRefreshing = false) {mPullRefreshing = true; mHeaderView. setState (XLi StViewHeader. STATE_REFRESHING); mHeaderView. setVisiableHeight (90); if (mListViewListener! = Null) {mListViewListener. onRefresh () ;}}/ *** stop load more, reset footer view. */public void stopLoadMore () {if (mPullLoading = true) {mPullLoading = false ;}} /*** set last refresh time *** @ param time */public void setRefreshTime (String time) {mHeaderTimeView. setText (time);} private void invokeOnScrolling () {if (mScrollListener instanceof OnXScrollListener) {OnXScrollListener l = (OnXScrollLis Tener) mScrollListener; l. onXScrolling (this) ;}} 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);} if (mPullLoading) {// disable, hide the contentmHeaderViewContent. setVisibility (View. INVISIBLE);} else {mHeaderViewContent. setVisibility (View. VISIBLE) ;}} 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 (mPullR Efreshing & height> mHeaderViewHeight) {finalHeight = mHeaderViewHeight;} mScrollBack = SCROLLBACK_HEADER; mScroller. startScroll (0, height, 0, finalHeight-height, SCROLL_DURATION); // trigger computeScrollinvalidate ();}/*** touch screen listener */@ Overridepublic boolean onTouchEvent (MotionEvent ev) {if (mLastY =-1) {mLastY = ev. getRawY ();} switch (ev. getAction () {case MotionEvent. ACTION_DOWN: mLastY = ev. getRaw Y (); break; case MotionEvent. ACTION_MOVE: final float deltaY = ev. getRawY ()-mLastY; // DLog. I (TAG, "deltaY is" + deltaY); 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 () = mTotal ItemCount-1) {// last item, already pulled up or want to pull up .} break; default: mLastY =-1; // resetif (getFirstVisiblePosition () = 0) {// invoke refreshif (! MPullRefreshing & mEnablePullRefresh &&! MPullLoading & mHeaderView. getVisiableHeight ()> mHeaderViewHeight) {mPullRefreshing = true; mHeaderView. setState (XListViewHeader. STATE_REFRESHING); // DLog. I (TAG, "invoke refresh"); if (mListViewListener! = Null) {// execute the new method mListViewListener. onRefresh () ;}} resetHeaderHeight ();} else if (getLastVisiblePosition () = mTotalItemCount-1) {// invoke load more. if (! MPullLoading & mEnablePullLoad &&! MPullRefreshing) {// DLog. I (TAG, "invoke load more") ;}} break;} return super. onTouchEvent (ev) ;}@ Overridepublic void computeScroll () {if (mScroller. computescroloffset () {if (mScrollBack = SCROLLBACK_HEADER) {mHeaderView. setVisiableHeight (mScroller. getCurrY ();} else {} postInvalidate (); invokeOnScrolling ();} super. computeScroll () ;}@ Overridepublic void setOnScrollListener (OnScrollListener l) {mScrollLi Stener = l;}/*** calls back when rolling. The callback is 2-3 times. If you don't leave your finger blank, the callback is 2 times. If scrollState is 2, the callback is not performed for 1st times: scrollState = * SCROLL_STATE_TOUCH_SCROLL (1) rolling 2nd times: scrollState = * SCROLL_STATE_FLING (2) the finger throws (slide hard before leaving the screen) for 3rd Times: scrollState = * SCROLL_STATE_IDLE (0) Stop rolling */@ Overridepublic void onScrollStateChanged (AbsListView view, int scrollState) {if (mScrollListener! = Null) {mScrollListener. onScrollStateChanged (view, scrollState);} // load more automatically when sliding to the bottom. You can also disable this logic if (getLastVisiblePosition () = mTotalItemCount-1 & scrollState = SCROLL_STATE_IDLE) {if (! MPullLoading & mEnablePullLoad &&! MPullRefreshing) {// DLog. I (TAG, "invoke load more") ;}}/*** calls back when rolling is in progress, and stops the callback only when the rolling is stopped, call back once when you click */@ Overridepublic void onScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {// send to user's quota = totalItemCount; if (rollmsclistener! = Null) {mScrollListener. onScroll (view, firstVisibleItem, visibleItemCount, totalItemCount) ;}} public void setXListViewListener (IXListViewListener l) {mListViewListener = l ;} /*** listen to the ListView sliding event ** @ author cyf **/public interface OnXScrollListener extends OnScrollListener {public void onXScrolling (View view );} /*** custom interface */public interface IXListViewListener {// The method of public void onRefresh () executed during the pull-down refresh (); // public void onLoadMore ();}}
In the xml file of MainActivity, do not use the android ListView instead. Use the custom ListView above (with the package name)
Package com. test. andy; import java. util. arrayList; import com. test. andy. view. XListView; import com. test. andy. view. XListView. IXListViewListener; import com. test. andy. r; import android. app. activity; import android. OS. bundle; import android. OS. handler; import android. widget. arrayAdapter;/*** XListViewActivity * implements the IXListViewListener interface to implement the drop-down and refresh methods. * @ author cyf **/public class XListViewActivity extends Act Ivity implements IXListViewListener {// custom ListViewprivate XListView mListView; private ArrayAdapter <String> mAdapter; private ArrayList <String> items = new ArrayList <String> (); private Handler mHandler; private int start = 0; private int refreshCnt = 0;/** Called when the activity is first created. * // @ Overridepublic void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setConten TView (R. layout. main); // load 20 pieces of data during initialization (geneItems (); mListView = (XListView) findViewById (R. id. xListView); mListView. setPullLoadEnable (true); mAdapter = new ArrayAdapter <String> (this, R. layout. list_item, items); mListView. setAdapter (mAdapter); // mListView. setPullRefreshEnable (false); mListView. setXListViewListener (this); mHandler = new Handler (); mListView. startRefresh ();} private void geneItems () {for (int I = 0; I! = 20; ++ I) {items. add ("refresh cnt" + (++ start) ;}} private void onLoad () {mListView. stopRefresh (); mListView. stopLoadMore (); mListView. setRefreshTime ("just") ;}@ Overridepublic void onRefresh () {mHandler. postDelayed (new Runnable () {@ Overridepublic void run () {start = ++ refreshCnt; items. clear (); geneItems (); // mAdapter. notifyDataSetChanged (); mAdapter = new ArrayAdapter <String> (XListViewActivity. this, R. layout. list_item, items); mListView. setAdapter (mAdapter); onLoad () ;}, 2000) ;}@ Overridepublic void onLoadMore () {mHandler. postDelayed (new Runnable () {@ Overridepublic void run () {geneItems (); mAdapter. notifyDataSetChanged (); onLoad () ;}, 2000 );}}
The important code is summarized here. I hope to help you. Thank you.