I've written an article about the Drop-down Refresh control. Drop-down Refresh control Terminator:pulltorefreshlayout, and then see a lot of people and pull load more requirements, so on the previous Drop-down refresh control on the basis of the improvement, add the function of pull loading. Not only that, I've changed it to be universal for all view! You can use these two functions at your whim ~ ~
I made a demo of a large set that implemented the ListView, GridView, Expandablelistview, ScrollView, WebView, ImageView, TextView Drop-down refreshes and pull loads. The download address of the demo will be provided later, and the latest code has been uploaded to Github:https://github.com/jingchenustc/pulltorefreshandload
As is customary, the following will be a large wave of effects:
Demo home is also available to drop down the ListView, you can add a table at the bottom:
Listview:
Gridview:
Expandablelistview:
ScrollView:
WebView:
ImageView:
TextView:
Pretty good, huh? The final ImageView and TextView are the simplest and return true directly to the interface method below.
Increasing pull loading is simple, as with managing the Pull-down head, and managing a top-pulling head, it's not a bother; As for converting it to generic, you need to unify the view behavior, and for this I have defined an interface:
Package com.jingchen.pulltorefresh.pullableview;
Public interface pullable
{
/**
* To determine whether you can drop down if you do not need the pull function to return false
*
* @return True if you can drop otherwise return false
*/
& nbsp; boolean canpulldown ();
/**
* Determine if you can pull up , if you do not need the pull function, you can return false
*
* @return True returns false
*/
boolean canpullup ();
}& If you can pull up nbsp The
can be seen from the interface name as an interface that provides a way to determine whether or not to pull. This interface of the two methods, Canpulldown () is to determine when to pull down the method, Canpullup () is to determine when you can pull, I in the demo of the judgment is to slide to the top when you can pull down, slide to the bottom of the time can pull. All view needs to be pulled and pulled down to implement this interface. The back will giveThe realization of some view. First look at the improved custom layout pulltorefreshlayout, adding a pull head, and the view between the dropdown head and the top pull head is the Pullableview of the Pullable interface. Compared to the previous version, here are the changes need to note that the following:
1, the increase of the pull head, the corresponding increase in control variables.
2, pull the elimination of Content_view events to prevent false trigger no longer using reflection, directly set Event.setaction (Motionevent.action_cancel).
3. Eliminates the upheaval caused by multiple touches in the pull process.
4, no longer set the Content_view Ontoulistener, so that users can be more free to set the listener.
This pulltorefreshlayout is only responsible for managing three controls, and if a view requires a pull down function, then only the interface can be implemented. Here's a look at the Pulltorefreshlayout code, which reads a lot:
Package Com.jingchen.pulltorefresh;
Import Java.util.Timer;
Import Java.util.TimerTask;
Import Android.content.Context;
Import Android.graphics.Canvas;
Import android.graphics.LinearGradient;
Import Android.graphics.Paint;
Import Android.graphics.Paint.Style;
Import Android.graphics.RectF;
Import Android.graphics.Shader.TileMode;
Import Android.os.Handler;
Import Android.os.Message;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import android.view.MotionEvent;
Import Android.view.View;
Import Android.view.ViewGroup;
Import Android.view.animation.AnimationUtils;
Import Android.view.animation.LinearInterpolator;
Import android.view.animation.RotateAnimation;
Import Android.widget.RelativeLayout;
Import Android.widget.TextView;
Import com.jingchen.pulltorefresh.pullableview.Pullable; /** * Custom layout, used to manage three child controls, one of which is a drop-down header, a pullableview that contains content (can be any view that implements the Pullable interface), * There is also a pull head * * @author Chen Jing/Publ IC class Pulltorefreshlayout extends RelaTivelayout {public static final String TAG = "Pulltorefreshlayout";
Initial state public static final int INIT = 0;
Release flush public static final int release_to_refresh = 1;
Refreshing public static final int refreshing = 2;
Release load public static final int release_to_load = 3;
Loading public static final int LOADING = 4;
Operation completed public static final int done = 5;
Current status private int state = INIT;
Refresh callback interface private Onrefreshlistener Mlistener;
Refresh succeeded public static final int succeed = 0;
Refresh failed public static final int FAIL = 1;
Press Y-coordinate, the previous event point y-coordinate private float downY, lasty; Pull down the distance.
Note: Pulldowny and pullupy cannot be at the same time not for 0 public float pulldowny = 0;
Oberra's distance private float pullupy = 0;
Release refresh distance private float refreshdist = 200;
Release the loaded distance private float loadmoredist = 200;
Private MyTimer timer;
Rollback speed public float move_speed = 8;
First execution Layout Private Boolean islayout = false;
Sliding operations Private Boolean Istouch = False during the refresh process; // The sliding distance of the finger is more than that of the drop head, and the middle will change with the tangent function. Private float radio = 2;
The dropdown arrow of the rotary 180° animation private rotateanimation rotateanimation;
Uniform rotation Animation private rotateanimation refreshinganimation;
The dropdown head private View Refreshview;
Down-Pull arrows private View pullview;
The icon being refreshed private View refreshingview;
Refresh the results icon private View Refreshstateimageview;
Refresh Result: Success or failure private TextView refreshstatetextview;
Upper pull head private View Loadmoreview;
Oberra's Arrow private View Pullupview;
The icon being loaded private View loadingview;
Load result icon private View loadstateimageview;
Load Result: Success or failure private TextView loadstatetextview;
Realization of the Pullable interface view Private View Pullableview;
Filter multi-point touch private int mevents;
These two variables to control the direction of the pull, if not control, when the situation can be satisfied with the pull and can be pulled down when the private boolean canpulldown = true;
Private Boolean Canpullup = true; /** * Handler/Handler for automatic rollback updatehandler = new Handler () {@Override public void Handlemessage msg) {//rebound speed increases with lower pull distance movedeltay increase
Move_speed = (float) (8 + 5 * Math.tan (MATH.PI/2/Getmeasuredheight () * (Pulldowny + math.abs (pullupy)));
if (!istouch) {//is refreshing and hovering without pushing up, display "refreshing ..." if (state = refreshing && pulldowny <= refreshdist) {
Pulldowny = refreshdist;
Timer.cancel ();
else if (state = = LOADING &&-pullupy <= loadmoredist) {pullupy =-loadmoredist;
Timer.cancel ();
} if (Pulldowny > 0) pulldowny-= Move_speed;
else if (Pullupy < 0) Pullupy + = Move_speed;
if (Pulldowny < 0) {//has completed the rebound pulldowny = 0;
Pullview.clearanimation ();
It is possible to refresh when hiding the drop down, and only change the status if the current state is not being refreshed if (state!= refreshing && State!= LOADING) changestate (INIT);
Timer.cancel ();
} if (Pullupy > 0) {//completed rebound pullupy = 0;
Pullupview.clearanimation ();
It is possible to refresh when hiding the drop down, and only change the status if the current state is not being refreshed if (state!= refreshing && State!= LOADING) changestate (INIT);
Timer.cancel (); //Refresh layout, automatically invoke OnLayout requestlayouT ();
}
};
public void Setonrefreshlistener (Onrefreshlistener listener) {Mlistener = listener;
Public Pulltorefreshlayout {Super (context);
Initview (context);
Public Pulltorefreshlayout (context, AttributeSet attrs) {Super (context, attrs);
Initview (context);
Public Pulltorefreshlayout (context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle);
Initview (context);
private void Initview {timer = new MyTimer (Updatehandler);
Rotateanimation = (rotateanimation) animationutils.loadanimation (context, R.anim.reverse_anim);
Refreshinganimation = (rotateanimation) animationutils.loadanimation (context, r.anim.rotating);
Add Shiting animation Linearinterpolator lir = new Linearinterpolator ();
Rotateanimation.setinterpolator (LIR);
Refreshinganimation.setinterpolator (LIR);
private void Hide () {timer.schedule (5); /** * Completes the refresh operation and displays the result of the refresh. Attention:Be sure to call this method when the refresh is complete * */** * @param refreshresult * Pulltorefreshlayout.succeed representative of Success, PULLTOREFRESHLAYOUT.FAIL representative failure * *
public void refreshfinish (int refreshresult) {refreshingview.clearanimation ();
Refreshingview.setvisibility (View.gone);
Switch (refreshresult) {case SUCCEED://Refresh successful refreshstateimageview.setvisibility (view.visible);
Refreshstatetextview.settext (R.string.refresh_succeed);
Refreshstateimageview. Setbackgroundresource (R.drawable.refresh_succeed);
Break
Case Fail:default://Refresh failed refreshstateimageview.setvisibility (view.visible);
Refreshstatetextview.settext (R.string.refresh_fail);
Refreshstateimageview. Setbackgroundresource (r.drawable.refresh_failed);
Break
//Refresh result stay 1 seconds New Handler () {@Override public void Handlemessage (msg) {changestate (done);
Hide ();
}}.sendemptymessagedelayed (0, 1000); /** * Load completed, display load results. Note: Be sure to call this method when the load is complete * * @param refreshresult * pulltorefreshlayout.Succeed represents success, Pulltorefreshlayout.fail represents failure */public void loadmorefinish (int refreshresult) {Loadingview.clearanima
tion ();
Loadingview.setvisibility (View.gone);
Switch (refreshresult) {case SUCCEED://Loaded successfully loadstateimageview.setvisibility (view.visible);
Loadstatetextview.settext (R.string.load_succeed);
Loadstateimageview.setbackgroundresource (R.drawable.load_succeed);
Break
Case Fail:default://Loading Failure loadstateimageview.setvisibility (view.visible);
Loadstatetextview.settext (R.string.load_fail);
Loadstateimageview.setbackgroundresource (r.drawable.load_failed);
Break
//Refresh result stay 1 seconds New Handler () {@Override public void Handlemessage (msg) {changestate (done);
Hide ();
}}.sendemptymessagedelayed (0, 1000);
private void Changestate (int to) {state = to;
Switch (state) {case INIT://Drop-down Layout initial status refreshstateimageview.setvisibility (View.gone);
Refreshstatetextview.settext (R.string.pull_to_refresh);Pullview.clearanimation ();
Pullview.setvisibility (view.visible);
The initial state loadstateimageview.setvisibility (View.gone) of the pull layout;
Loadstatetextview.settext (R.string.pullup_to_load);
Pullupview.clearanimation ();
Pullupview.setvisibility (view.visible);
Break
Case Release_to_refresh://Release Refresh Status Refreshstatetextview.settext (R.string.release_to_refresh);
Pullview.startanimation (rotateanimation);
Break
Case refreshing://Is refreshing state pullview.clearanimation ();
Refreshingview.setvisibility (view.visible);
Pullview.setvisibility (view.invisible);
Refreshingview.startanimation (refreshinganimation);
Refreshstatetextview.settext (r.string.refreshing);
Break
Case Release_to_load://Release loading state loadstatetextview.settext (r.string.release_to_load);
Pullupview.startanimation (rotateanimation);
Break
Case LOADING://Loading State pullupview.clearanimation ();
Loadingview.setvisibility (view.visible);
Pullupview.setvisibility (view.invisible); Loadingview.startanimatioN (refreshinganimation);
Loadstatetextview.settext (r.string.loading);
Break
Case done://Refresh or load finished, nothing to do break;
}/** * does not restrict pull or drop/private void Releasepull () {Canpulldown = true;
Canpullup = true; /* * (non-Javadoc) determines whether events are distributed by the parent control, preventing event conflicts * * @see android.view.viewgroup#dispatchtouchevent (android.view.MotionEven T) */@Override public boolean dispatchtouchevent (motionevent ev) {switch (ev.getactionmasked ()) {case Mot
IonEvent.ACTION_DOWN:downY = Ev.gety ();
Lasty = DownY;
Timer.cancel ();
mevents = 0;
Releasepull ();
Break
Case MotionEvent.ACTION_POINTER_DOWN:case MOTIONEVENT.ACTION_POINTER_UP://Filter Multi-touch mevents =-1;
Break
Case MotionEvent.ACTION_MOVE:if (mevents = = 0) {if ((pullable) pullableview). Canpulldown () && Canpulldown && State!= LOADING) {//Can be pulled down, cannot pull down when loading//the actual sliding distance do shrink, resulting in the feeling of force pulling pulldowny = Pulldowny + (ev.gety ()
-lasty)/radio;
if (Pulldowny < 0) {pulldowny = 0;
Canpulldown = false;
Canpullup = true;
} if (Pulldowny > Getmeasuredheight ()) Pulldowny = Getmeasuredheight ();
if (state = = refreshing) {//is refreshing when the touch moves Istouch = true; } else if ((pullable) pullableview). Canpullup () && canpullup && State!= refreshing) {//Can be on
Pull, is refreshing cannot pull pullupy = Pullupy + (ev.gety ()-lasty)/radio;
if (Pullupy > 0) {pullupy = 0;
Canpulldown = true;
Canpullup = false;
} if (Pullupy <-getmeasuredheight ()) Pullupy =-getmeasuredheight ();
if (state = = LOADING) {//is loading when the touch moves Istouch = true;
} else Releasepull ();
else mevents = 0;
Lasty = Ev.gety (); Change the proportional radio = (float) (2 + 2 * Math.tan (MATH.PI/2/Getmeasuredheight () * (Pulldowny + math.abs (pullupy))) According to the drop distance
;
Requestlayout (); if (pulldowny <= refreshdist <span style= "White-space:pre" > </span>&& (state = = Release_to_refre SH | | State = = done)) {<span style= "White-space:pre" > </span>//if the drop distance does not reach the refresh distance and the current state is a release refresh, the change status is Drop-down refresh <span
"White-space:pre" > </span>changestate (INIT); <span style= "White-space:pre" > </span>} <span style= "White-space:pre" > </span>if (PullDownY >= refreshdist && (state = INIT | | state = = done)) {<span style= "White-space:pre" > </span>//if Pull distance to reach refresh distance and current state is initial state refresh, change state to release refresh <span style= "White-space:pre" > </span>changestate (Release_to_refresh
); <span style= "White-space:pre" > </span> <span style= "White-space:pre" > </span>//The following is the judgment pull load, Ditto, note that pullupy is negative <span style= "White-space:pre" > </span>if (-pullupy <= loadmoredist <span style= " White-space:pre "> </span>&& (state = = Release_to_load | |)" {<span style= "White-space:
Pre "> </span>changestate (INIT); <span style= "White-space:pre" > </span>} <span style= "WHite-space:pre "> </span>if (-pullupy >= loadmoredist && (state = = INIT | | state = = done)) {<span
style= "White-space:pre" > </span>changestate (release_to_load);
<span style= "White-space:pre" > </span>}//Because the refresh and load operations cannot be performed at the same time, Pulldowny and Pullupy will not be 0 at the same time, so it is used here (Pulldowny + Math.Abs (pullupy)) can not differentiate the current state of the IF ((Pulldowny + math.abs (pullupy)) > 8) {//Prevent the drop down process from triggering a long press event and click events ev.setacti
On (Motionevent.action_cancel);
} break; Case MotionEvent.ACTION_UP:if (Pulldowny > Refreshdist | |-pullupy > loadmoredist)//Pull down when refreshing (pull up when loading), drop down after release
(top pull) does not hide Istouch = false;
if (state = = Release_to_refresh) {changestate (refreshing);
The refresh operation if (Mlistener!= null) Mlistener.onrefresh (this);
else if (state = = Release_to_load) {changestate (LOADING);
Load operation if (Mlistener!= null) Mlistener.onloadmore (this);
Hide ();
Default:break;
//Event distribution to parent class super.dispatchtouchevent (EV);
return true;
}
private void Initview () {//init drop-down layout Pullview = Refreshview.findviewbyid (R.id.pull_icon);
Refreshstatetextview = (TextView) refreshview. Findviewbyid (R.ID.STATE_TV);
Refreshingview = Refreshview.findviewbyid (R.id.refreshing_icon);
Refreshstateimageview = Refreshview.findviewbyid (R.ID.STATE_IV);
Initialize the pull layout Pullupview = Loadmoreview.findviewbyid (R.id.pullup_icon);
Loadstatetextview = (TextView) loadmoreview. Findviewbyid (R.ID.LOADSTATE_TV);
Loadingview = Loadmoreview.findviewbyid (R.id.loading_icon);
Loadstateimageview = Loadmoreview.findviewbyid (R.ID.LOADSTATE_IV); @Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {if (!islayout) {//here is the first
When you come in, do some initialization refreshview = getchildat (0);
Pullableview = Getchildat (1);
Loadmoreview = Getchildat (2);
Islayout = true;
Initview ();
Refreshdist = ((ViewGroup) refreshview). Getchildat (0). Getmeasuredheight (); Loadmoredist = ((ViewGroup) loadmoreview). Getchildat (0). Getmeasuredheight (); //Change the layout of the child control, which is used directly as an offset (pulldowny + pullupy) so that the current state can not be differentiated refreshview.layout (0, (int) (Pulldowny + pullupy)-ref
Reshview.getmeasuredheight (), Refreshview.getmeasuredwidth (), (int) (Pulldowny + pullupy)); Pullableview.layout (0, (int) (Pulldowny + pullupy), Pullableview.getmeasuredwidth (), (int) (Pulldowny + pullupy) + PU
Llableview.getmeasuredheight ()); Loadmoreview.layout (0, (int) (Pulldowny + pullupy) + pullableview.getmeasuredheight (), Loadmoreview.getmeasuredwidth (
), (int) (Pulldowny + pullupy) + pullableview.getmeasuredheight () + loadmoreview.getmeasuredheight ());
Class MyTimer {private Handler Handler;
private timer timer;
Private MyTask Mtask;
Public MyTimer (Handler Handler) {this.handler = Handler;
Timer = new timer ();
public void schedule (long period) {if (mtask!= null) {mtask.cancel ();
Mtask = null;
} mtask = new MyTask (handler);
Timer.schedule (mtask, 0, period); public void Cancel () {if (mtask!= null) {mtask.cancel ();
Mtask = null;
} class MyTask extends TimerTask {private Handler Handler;
Public MyTask (Handler Handler) {this.handler = Handler;
@Override public void Run () {handler.obtainmessage (). Sendtotarget ();
/** * Refresh Load Callback interface * * @author chenjing * */public interface Onrefreshlistener {/** * Refresh operation
* * void Onrefresh (pulltorefreshlayout pulltorefreshlayout);
/** * Loading operation/void Onloadmore (Pulltorefreshlayout pulltorefreshlayout);
}
}
The
Above is the entire layout of the code, it is not difficult.
Look at the implementation of the Pullable interface for each view, ListView and GridView and Expandablelistview are the same way to judge:
Pullablelistview:
package com.jingchen.pulltorefresh.pullableview;
Import Android.content.Context;
Import Android.util.AttributeSet;
Import Android.util.Log;
Import Android.widget.ListView; public class Pullablelistview extends ListView implements pullable {public Pullablelistview (context context) {s
Uper (context);
Public Pullablelistview (context, AttributeSet attrs) {Super (context, attrs);
Public Pullablelistview (context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle);
@Override public boolean Canpulldown () {if (GetCount () = 0) {//No item can also be pulled down to refresh return true; else if (getfirstvisibleposition () = = 0 && getchildat (0). GetTop () >= 0) {//slide to the top of the ListView return TR
Ue
else return false;
@Override public boolean Canpullup () {if (GetCount () = 0) {//No item can also be pulled to load return true; else if (getlastvisibleposition () = = (gEtcount ()-1)) {//sliding to the bottom of the IF (Getchildat (Getlastvisibleposition ()-getfirstvisibleposition ())!= null && ; Getchildat (Getlastvisibleposition ()-getfirstvisibleposition ()). Getbottom () <= getmeasuredheight ()) return T
Rue
return false; }
}
Pullableexpandablelistview:
package com.jingchen.pulltorefresh.pullableview;
Import Android.content.Context;
Import Android.util.AttributeSet;
Import Android.widget.ExpandableListView; public class Pullableexpandablelistview extends Expandablelistview implements pullable {public pullableexpandablel
Istview (context) {super (context);
Public Pullableexpandablelistview (context, AttributeSet attrs) {Super (context, attrs); Pullableexpandablelistview (context, AttributeSet attrs, int defstyle) {Super (context, attrs, D
Efstyle);
@Override public boolean Canpulldown () {if (GetCount () = 0) {//No item can also be pulled down to refresh return true;
else if (getfirstvisibleposition () = = 0 && getchildat (0). GetTop () >= 0) {//sliding to the top of return true;
else return false;
@Override public boolean Canpullup () {if (GetCount () = 0) {//No item can also be pulled to load return true; else if (gEtlastvisibleposition () = = (GetCount ()-1)) {//slide to the bottom of the IF (Getchildat (Getlastvisibleposition ()-Getfirstvisiblepos Ition ())!= null && getchildat (getlastvisibleposition ()-getfirstvisibleposition ()). Getbottom () <=
Getmeasuredheight ()) return true;
return false; }
}
Pullablegridview:
package com.jingchen.pulltorefresh.pullableview;
Import Android.content.Context;
Import Android.util.AttributeSet;
Import Android.widget.GridView; public class Pullablegridview extends GridView implements pullable {public Pullablegridview (context context) {s
Uper (context);
Public Pullablegridview (context, AttributeSet attrs) {Super (context, attrs);
Public Pullablegridview (context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle);
@Override public boolean Canpulldown () {if (GetCount () = 0) {//No item can also be pulled down to refresh return true;
else if (getfirstvisibleposition () = = 0 && getchildat (0). GetTop () >= 0) {//sliding to the top of return true;
else return false;
@Override public boolean Canpullup () {if (GetCount () = 0) {//No item can also be pulled to load return true; else if (getlastvisibleposition () = = (GetCount ()-1)) {//slide to the bottom of the IF (Getchildat (Getlastvisibleposition ()-getfirstvisibleposition ())!= null && getchildat (Getlastvisibleposi
tion ()-getfirstvisibleposition ()). Getbottom () <= getmeasuredheight ()) return true;
return false; }
}
Pullablescrollview:
Package Com.jingchen.pulltorefresh.pullableview;
Import Android.content.Context;
Import Android.util.AttributeSet;
Import Android.widget.ScrollView;
public class Pullablescrollview extends ScrollView implements pullable
{public
Pullablescrollview Context)
{
super (context);
}
Public Pullablescrollview (context, AttributeSet attrs)
{
Super (context, attrs);
}
Public Pullablescrollview (context, AttributeSet attrs, int defstyle)
{
Super (context, attrs, Defstyle);
}
@Override Public
Boolean canpulldown ()
{
if (getscrolly () = 0) return
true;
else return
false;
@Override Public
Boolean Canpullup ()
{
if (getscrolly) >= (Getchildat (0). GetHeight ()- Getmeasuredheight ()) return
true;
else return
false;
Pullablewebview:
Package Com.jingchen.pulltorefresh.pullableview;
Import Android.content.Context;
Import Android.util.AttributeSet;
Import Android.webkit.WebView;
public class Pullablewebview extends WebView implements pullable
{public
Pullablewebview
{
super (context);
}
Public Pullablewebview (context, AttributeSet attrs)
{
Super (context, attrs);
}
Public Pullablewebview (context, AttributeSet attrs, int defstyle)
{
Super (context, attrs, Defstyle);
}
@Override Public
Boolean canpulldown ()
{
if (getscrolly () = 0) return
true;
else return
false;
@Override Public
Boolean Canpullup ()
{
if (getscrolly () >= getcontentheight () * Getscale ()
- Getmeasuredheight ()) return
true;
else return
false;
}
ImageView and TextView are not posted, I returned true directly in the method.
SOURCE Download: general release Drop-down refresh load Dahe Set demo
Wonderful topic sharing: Javascriptandroid loading feature summary
This article has been sorted into the "Android Drop-down refresh loading effect," Welcome to study.
I hope this article is helpful for you to learn about the Android pull down refresh load control.