Reprint Please specify source: http://blog.csdn.net/bettarwang/article/details/41634729
Before the online also see some so-called drop-down refresh example, but the total feeling is to complicate the simple things, often more than 300 lines or even more than 600 lines of code, in fact, the main thing is to respond to the touch event, there is no need to be so troublesome. Next, implement a ListView that can be pulled up and down, and then implement a ListView with a header that can be refreshed:
The source of the ListView can be pulled up and down as follows:
/** * Can be pulled up and down the ListView * @author Bettar * */public class Refreshablelistview extends listview{private static final String TA G= "Refreshablelistview";p rivate int touchslop;private int inittopmargin;//private int inittopoffirstchild;private Boolean hasrecord=false;private float starty;private boolean ispulling=false;//private viewgroup.layoutparams params; Private Linearlayout.layoutparams Params;public Refreshablelistview (context context, AttributeSet Attrs) {super ( context, attrs);//This allows the setting parameters to be read in so that there is no conflict with the layout file settings. Params=new linearlayout.layoutparams (context, attrs); Inittopmargin=params.topmargin;this.setlayoutparams (params) ; Touchslop=viewconfiguration.get (context). Gettouchslop ();} @Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {Case MotionEvent.ACTION_DOWN:if ( !hasrecord) {hasrecord=true;starty=event.gety (); LOG.I (TAG, "Action_down");} Break;case MotionEvent.ACTION_MOVE:float distance=event.gety ()-starty;if (!ispulling) {if (!couldpull (distance)) { Log.i(TAG, "could not pulled in Action_move"); return false; }} ispulling=true; LOG.I (TAG, "pull in Action_move"); Params.topmargin+=distance; This.setlayoutparams (params); This.setpressed (FALSE); This.setfocusable (FALSE); This.setfocusableintouchmode (FALSE); Return true;case motionevent.action_up:log.i (TAG, "action_up");p Arams.topmargin=inittopmargin; This.setlayoutparams (params); hasrecord=false;this.setfocusable (true); This.setfocusableintouchmode (true); if ( ispulling) {ispulling=false;//Note: You must return TRUE if the post is stretched, otherwise this event will also be read by other event handlers, affecting the external operations of the class, such as operations in Setonitemclicklistener. return true;} Ispulling=false;break;} Return Super.ontouchevent (event);} Private Boolean couldpull (float distance) {if (Math.Abs (distance) <touchslop) {return false;} if (distance>0) {log.i (TAG, "GetTop ()" +this.gettop ()); if (This.getfirstvisibleposition () ==0&& This.getchildat (0). GetTop () ==0) {return true;}} Else{if (This.getlastvisibleposition () ==this.getcount ()-1) {return true;}} return false;}}
One of the details to be aware of is the processing of action_up, if the action_up of the finger is released after stretching, then return true instead of false, otherwise it will affect the normal use of this custom ListView. Because if you return false, this whole process will be treated as a click, because of the Action_down and action_up, thus affecting the additional impact.
If you want to add a certain animation, it is also very simple, using a tweened animation or asynchronous task to implement, the following code uses two implementations:
Package Com.android.customview;import Android.content.context;import Android.os.asynctask;import Android.util.attributeset;import Android.util.log;import Android.view.motionevent;import Android.view.viewconfiguration;import Android.view.viewgroup;import android.view.animation.TranslateAnimation; Import Android.widget.abslistview;import android.widget.linearlayout;import android.widget.listview;/** * The ListView can be pulled up and down * @author Bettar * */public class Refreshablelistview extends listview{private static final String tag= "Ref Reshablelistview ",//0.5 words will feel very sticky, and 1.0 words and feel too slippery, 0.8 is a better parameter. Private static final float ratio=0.8f;private static final int anim_duration=1000;private int touchslop;private int Initto Pmargin;private int[]initlocation=new int[2];p rivate boolean hasrecord=false;private float Starty;private boolean Ispulling=false;//private viewgroup.layoutparams params;private linearlayout.layoutparams params;public Refreshablelistview (context context, AttributeSet Attrs) {Super (context, attrs)//params=this.getlayoutparams ();//This allows the setting parameters to be read in so that there is no conflict with the layout file settings. Params=new linearlayout.layoutparams (context, attrs); Inittopmargin=params.topmargin;this.getlocationonscreen ( initlocation);//inittopoffirstchild=this.getchildat (0). GetTop (); This.setlayoutparams (params); touchslop= Viewconfiguration.get (context). Gettouchslop ();} @Overridepublic boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {Case MotionEvent.ACTION_DOWN:if ( !hasrecord) {hasrecord=true;starty=event.gety (); LOG.I (TAG, "Action_down");} Break;case MotionEvent.ACTION_MOVE:float distance=event.gety ()-starty;if (!ispulling) {if (!couldpull (distance)) { LOG.I (TAG, "could not pulled in Action_move"); return false; }} ispulling=true; LOG.I (TAG, "pull in Action_move"); params.topmargin=inittopmargin+ (int) (distance*ratio); This.setlayoutparams (params); This.setpressed (FALSE); This.setfocusable (FALSE); This.setfocusableintouchmode (FALSE); return True;case Motionevent.action_uP:LOG.I (TAG, "action_up"), if (ispulling) {starttranslateanimation ();//executetranslateanimation ();} Reset the parameters, note that if you are using custom animations, reset () will be here, and then reset () until the asynchronous task finishes executing, otherwise the parameters will interfere with each other. Reset (); if (ispulling) {ispulling=false;//Note: You must return TRUE if the post is stretched, otherwise this event will also be read by other event handlers, affecting the external operation of the class. such as operations in the Setonitemclicklistener. return true;} Ispulling=false;break;} Return Super.ontouchevent (event);} private void Reset () {params.topmargin=inittopmargin;this.setlayoutparams (params); hasrecord=false; This.setfocusable (True); This.setfocusableintouchmode (true);} private void Starttranslateanimation () {int[]location=new int[2]; RefreshableListView.this.getLocationOnScreen (location);//test finds location[0]==0 and Location[1] is the distance from the top of the first item. LOG.I (TAG, "location[0]=" +location[0]+ "location[1]=" +location[1]); Translateanimation anim=new translateanimation (location[0],initlocation[0],location[1],initlocation[1]); Anim.setduration (anim_duration); RefreshableListView.this.startAnimation (ANIM);} /** * This is actually the equivalent of self-realization animation. */private void Executetranslateanimation () {NEW Translatetask (). Execute ();} /** * If it is used, it is necessary to put the params parameters and so on after the completion of the asynchronous task execution, or it will now interfere with each other situation. * @author Bettar * */private class Translatetask extends asynctask<void,integer,integer>{//sleep time for each thread private int deltasleeptime;private int deltascrolly;public translatetask (int deltasleeptime) {this.deltasleeptime= Deltasleeptime;if (deltasleeptime>0) {deltascrolly=0-(Params.topmargin-inittopmargin)/(ANIM_DURATION/ Deltasleeptime);} else{deltascrolly=params.topmargin>inittopmargin?-20:20;} LOG.I (TAG, "deltascrolly=" +deltascrolly);} @Overrideprotected Integer Doinbackground (void...voidparams) {int Topmargin=params.topmargin;while (true) {TopMargin +=deltascrolly; LOG.I (TAG, "topmargin=" +topmargin); if (deltascrolly<0) {if (topmargin<0) {topmargin=0;break;}} Else{if (topmargin>0) {topmargin=0;break;}} Publishprogress (TopMargin); Try{thread.sleep (deltasleeptime);} catch (Interruptedexception ex) {ex.printstacktrace ();}} Publishprogress (0); return topMargin;} @Overrideprotected void Onprogressupdate (Integer ... valUES) {//values[0] corresponds to TOPMARGINLOG.I in the above publisprogress (TAG, "values[0" i.e topmargin= "+values[0]);p arams.topmargin= Values[0]; RefreshableListView.this.setLayoutParams (params);} @Overrideprotected void OnPostExecute (Integer result) {//After executing the asynchronous task, the parameters can be reset reset ();}} /** * Determines whether a pull can be started, and if it is pulled down, the first item is fully visible, and if it is pulled up, the last item is fully visible. * @param distance * @return */private boolean couldpull (float distance) {if (Math.Abs (distance) <touchslop) {return false;} if (distance>0) {log.i (TAG, "GetTop ()" +this.gettop ()); if (This.getfirstvisibleposition () ==0&& This.getchildat (0). GetTop () ==0)//if (This.getfirstvisibleposition () ==0&&this.getchildat (0). GetTop () = = Inittopoffirstchild) {return true;}} Else{if (This.getlastvisibleposition () ==this.getcount ()-1) {return true;}} return false;}}
Believe that here, to do a pull down the refresh head of the ListView is very simple, today first come here, pull down the refreshed code behind.
100 lines of code in Android implement a custom ListView that can be pulled up and down