Sina Weibo and the QQ space all have the pull-down refresh effect, and many others are looking at it and analyzing it in detail. The principle turns out to be the same.
On the basis of the original author, I wrote some comments to help you better read and understand them. (maybe some of the comments are incorrect. please correct me. Thank you)
Source code: http://download.csdn.net/detail/weidi1989/4588246
Let's take a look:
Next, we will display the key code, a custom mylistview:
/*** Override a listview by adding a drop-down event ** @ author way **/public class mylistview extends listview implements onscrolllistener {Private Static final string tag = "listview "; private Final Static int release_to_refresh = 0; // release the refresh State private final static int pull_to_refresh = 1; // pull the refresh State private final static int refreshing = 2; // refreshing private final static int done = 3; // Private Final Static int Load Ing = 4; // loading data status private final static int ratio = 3; // ratio of actual padding distance to interface offset private layoutinflater Inflater; private linearlayout headview; // viewprivate textview tipstextview in the listview header; // message "pull-down refresh" textviewprivate textview lastupdatedtextview; // textviewprivate imageview arrowimageview at the last update time; // The Private progressbar of the arrow; // refresh the progress Private rotateanimation animation; // The arrow down the animation private R Otateanimation reverseanimation; // reverse arrow animation private Boolean isrecored; // used to ensure that the value of starty is recorded only once in a complete touch event; // The width of the header View content private int headcontentheight; // The height of the header View content private int starty; // when the touch-down event occurs, the finger starts from the y-axis position private int firstitemindex; // The index private int state of the first item of listview; // refresh status private Boolean isback; // whether to rebound private onrefreshlistener refreshlistener; // The refresh interface private Boolean is reserved for the outside Refreshable; // whether to refresh the flag space/*** the first constructor ** @ Param context * context object */Public mylistview (context) {super (context ); init (context);}/*** second constructor ** @ Param context * context object * @ Param attrs * attribute */Public mylistview (context, attributeset attrs) {super (context, attrs); Init (context) ;}/ *** initialize data ** @ Param context * context object */private void Init (context) {// setcachecolorhint (context. getresou Rces (). getcolor (R. color. transparent); Inflater = layoutinflater. from (context); headview = (linearlayout) Inflater. inflate (R. layout. head, null); // obtain the viewarrowimageview = (imageview) headview of the listview header. findviewbyid (R. id. head_arrowimageview); // obtain the arrow image arrowimageview from the view in the header. setminimumwidth (70); arrowimageview. setminimumheight (50); progressbar = (progressbar) headview. findviewbyid (R. id. head_progressbar ); // Obtain the refresh progress bar tipstextview = (textview) headview. findviewbyid (R. id. head_tipstextview); // textviewlastupdatedtextview = (textview) headview of the message. findviewbyid (R. id. head_lastupdatedtextview); // textviewmeasureview (headview) of the last refresh time; // a self-written method that does not fully understand headcontentheight = headview. getmeasuredheight (); // obtain the original headview height. headcontentwidth = headview. getmeasuredwidth (); headview. setpadding (0,-1 * headcontentheight, 0, 0); // sets the internal offset headview of the content. invalidate (); log. V ("size", "width:" + headcontentwidth + "height:" + headcontentheight); addheaderview (headview, null, false); // Add it to the listview header view, the listview component provides two very useful functions, that is, you can add a custom view setonscrolllistener (this) at the top and bottom; // arrow down animation = new rotateanimation (0, -180, rotateanimation. relative_to_self, 0.5f, rotateanimation. relative_to_self, 0.5f); animation. setinterpolator (New Linearinterpolator (); animation. setduration (250); animation. setfillafter (true); // reverse arrow animation reverseanimation = new rotateanimation (-180, 0, rotateanimation. relative_to_self, 0.5f, rotateanimation. relative_to_self, 0.5f); reverseanimation. setinterpolator (New linearinterpolator (); reverseanimation. setduration (200); reverseanimation. setfillafter (true); State = done; // isrefreshable = false when the default completion state is loaded for the first time; // refresh the flag The default value is false}/*** called when sliding */Public void onscroll (abslistview view, int firstvisiableitem, int visibleitemcount, int totalitemcount) {firstitemindex = firstvisiableitem; // The first index value of listview is the first visible item in the listview data}/*** called when the sliding status changes */Public void onscrollstatechanged (abslistview view, int scrollstate) {}/*** touch event */Public Boolean ontouchevent (motionevent event) {If (isrefreshable) {// If the refresh flag is trueswitch (event. ge Taction () {Case motionevent. action_down: // downward if (firstitemindex = 0 &&! Isrecored) {isrecored = true; starty = (INT) event. gety (); log. V (TAG, "record current position when down");} break; Case motionevent. action_up: // up if (State! = Refreshing & state! = Loading) {If (State = done) {// do nothing} If (State = pull_to_refresh) {// refresh state = done from the drop-down list; changeheaderviewbystate (); // update the viewlog header. V (TAG, "Refresh from drop-down to done status");} If (State = release_to_refresh) {// release refresh state = refreshing; changeheaderviewbystate (); onrefresh (); // call the interface method to notify the External Log. V (TAG, "from release refresh status to done status") ;}} isrecored = false; isback = false; break; Case motionevent. action_move: // move the finger to int Tempy = (INT) Eve NT. Gety (); If (! Isrecored & firstitemindex = 0) {log. V (TAG, "record location when moving"); isrecored = true; starty = Tempy;} If (State! = Refreshing & isrecored & state! = Loading) {// ensure that the current position is always in the head during the padding setting process. Otherwise, if the list exceeds the screen, when pushing, the list will scroll at the same time. // you can easily refresh the IF (State = release_to_refresh) {setselection (0); // push up to the extent that the screen is sufficient to cover up the head, however, it has not been pushed to the full-covered level. If (Tempy-starty)/ratio