Recyclerview has been out for a long time, but in the project before the use of ListView, the recent new projects have been a large number of use of recycleview. In particular, the waterfall flow of the Drop-down refresh, online bar is not the right to summarize their own a ha.
First map up to see:
Using Recyclerview to implement pull-load more and drop-refresh features I have two ways of doing it myself:
1. Use the Android.support.v4.widget.SwipeRefreshLayout of the system with this control price to achieve.
2. Custom-defined controls with Recyleview.
Using Recycleview is very difficult to add the head, before using ListView in which you can add headers and BOOTM, but Recycleview seems not so good operation. For the first use of the system from the Android.support.v4.widget.SwipeRefreshLayout to achieve, but also very useful, but the product generally do not pull this down to refresh, in order to make their own look good, he will usually engage in a own animation, which is more nonsense. So we can only use the Method 2.
Roughly say a Ha Method 2 implementation, the parent layout for ViewGroup, inside add view first for the control for the header second control for Recycleview, as for the bottom of the drop-down load more attempts, through the RECYCLEVIW adapter to add.
With the idea to get up:
Package Com.krain.srecyclerview.fruitview;
Import Android.content.Context;
Import android.graphics.drawable.AnimationDrawable;
Import Android.util.AttributeSet;
Import Android.view.LayoutInflater;
Import Android.view.View;
Import Android.widget.FrameLayout;
Import Android.widget.ImageView;
Import COM.KRAIN.SRECYCLERVIEW.R;
/** * Created by Dafushao on 2016/9/9 0009. * */public class Elizabethview extends Framelayout {private ImageView imageview; private animationdrawable Animationdraw
able; Public Elizabethview (context) {super (context); Initview (context); AttributeSet attrs) {Super (context, attrs); Initview (context);} public Elizabethview (context, AttributeSet attr s, int defstyleattr) {Super (context, attrs, defstyleattr); Initview (context);} private void Initview (context context) {V
Iew view= layoutinflater.from (context). Inflate (R.layout.elizabeth_item,null);
imageview= (ImageView) View.findviewbyid (R.ID.ELIZABETH_IM); AnimatIondrawable= (animationdrawable) imageview.getbackground ();
AddView (view); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {super.onmeasure (Widthmeasurespec,
HEIGHTMEASURESPEC);
//Start animation public void Startanim () {Animationdrawable.start ();}//Stop animation public void Stopanim () {animationdrawable.stop ();} }
This is the head control price is very simple inside there is a small smelly egg and the effect of squeezing a HA is not mapped.
The following is a custom control code containing Recyclerview as follows:
Package Com.krain.srecyclerview.srecyclerview;
Import Android.content.Context;
Import Android.os.Handler;
Import Android.os.Message;
Import Android.support.v4.view.MotionEventCompat;
Import Android.support.v7.widget.DefaultItemAnimator;
Import Android.support.v7.widget.GridLayoutManager;
Import Android.support.v7.widget.LinearLayoutManager;
Import Android.support.v7.widget.RecyclerView;
Import Android.support.v7.widget.StaggeredGridLayoutManager;
Import Android.util.AttributeSet;
Import Android.view.LayoutInflater;
Import android.view.MotionEvent;
Import Android.view.View;
Import Android.view.ViewGroup;
Import Android.widget.LinearLayout;
Import Android.widget.ProgressBar;
Import Android.widget.Scroller;
Import Android.widget.TextView;
Import COM.KRAIN.SRECYCLERVIEW.R;
Import Com.krain.srecyclerview.fruitview.ElizabethView;
public class Srecyclerview extends ViewGroup;
Recyclerview Mrecyclerview;
Elizabethview Mheaderview; TextView Mfootviewtips;//footview Text Display AdaptErwrapper Madapter;
Boolean mistop = true;//whether sliding to the top Recyclerview.layoutmanager Mlayoutmanager;
int Mlastvisibleitem;
int Mfirstvisibleitem;
Onrecyclerstatuschangelistener Mrecyclerchangelistener;
int mstatus;//The height of the current state int mheadviewheight;//headview scroller Mscroller; int mfristscollery;//The first getscrolly Boolean mhasfooter;//whether there is a pull loaded function Boolean mshowfootvisible;// Whether to display Footerview when Mhasfooter is true Boolean Mhasrefresh = true;//whether to support Drop-down refresh private final int default_min_pageindex = 1;// Default minimum number of pages int mmaxpage = default_min_pageindex;//total pages int mcurrentpage = default_min_pageindex;//Current number of pages, starting with 1 private
Final int status_normal = 0, Status_refresh = 1, status_load = 2; Private final int msg_load_complete = 1, Msg_refresh_complete = 0;//handle constant private final int delay_load_complete = 1000 , Delay_refresh_complete = 1000;//loading time to complete a deferred recycle public Srecyclerview (context) {super (context); init (context);} PU Blic Srecyclerview (context, AttributeSet attrs) {Super (context, attrs); Init (conText); Public Srecyclerview (context, AttributeSet attrs, int defstyleattr) {Super (context, attrs, defstyleattr); Init (
context); /** * Set maximum number of pages * * @param maxpage/public void setmaxpage (int maxpage) {this.mmaxpage = maxpage;}/** * Whether the pull load * is supported * * PARAM Hasloadmore */public void Setloadmore (Boolean hasloadmore) {mhasfooter = Hasloadmore;} public void Setrecyclervie Wlayoutmanage (Recyclerview.layoutmanager mlayoutmanage) {this.mlayoutmanager=mlayoutmanage}/** * Turn off the Drop-down refresh feature/public void Disablerefresh () {Mhasrefresh = false;} public void Setadapter (Baserecyclerviewadapter adapter) {int height = 0; i
F (mmaxpage = = default_min_pageindex) {Mhasfooter = false;} Madapter = new Adapterwrapper (context, adapter);
Mrecyclerview.setadapter (Madapter); private int getviewheight (view view) {int measure = View.MeasureSpec.makeMeasureSpec (0, View.MeasureSpec.UNSPECIFIED)
;
View.measure (measure, measure);
return View.getmeasuredheight (); /** * Get ViewGroup inside the recyclerview * * * @reTurn/Public Recyclerview Getrecyclerview () {return mrecyclerview.} public void Setonrecyclerchangelistener (onrecycle Rstatuschangelistener listener) {Mrecyclerchangelistener = listener;/** * Set recyclerview Add, delete item animation * * @param animat
OR/* public void Setitemanimator (Recyclerview.itemanimator animator) {mrecyclerview.setitemanimator (animator);}
public void notifydatasetchanged () {mstatus = status_normal;//re-set data represents Loadmore end, then revert to normal state
Madapter.notifydatasetchanged (); } public void Notifydatainsert (int positionstart, int itemCount) {mstatus = status_normal;//re Set data representative Loadmore is over.
At this time the normal state madapter.notifyitemrangeinserted (Positionstart, ItemCount) is restored;
The public void notifydataremove (int position) {Mstatus = status_normal;//re-set data represents the end of Loadmore, which is now restored to normal state
madapter.notifyitemremoved (position); /** * Initialization Operation * @param context/Void init (Context context) {This.context = context; Mscroller = new Scroller (context)
; if (mlayoutmanager!=null) {//Addchildview (Context,mlayoutmanaGER);
}else{//Addchildview (context, new linearlayoutmanager);//} Addchildview (context); @Override public void Computescroll () {if (Mscroller.computescrolloffset ()) {Scrollto (), Mscroller.getcurrx (),
Mscroller.getcurry ());
Postinvalidate (); }/** * Add child view * * @param context/void Addchildview (context context, Recyclerview.layoutmanager Mlayoutmanager) {Vi
Ewgroup.layoutparams params = new Viewgroup.layoutparams (layoutparams.match_parent, layoutparams.match_parent);
Mheaderview = new Elizabethview (context);
Mrecyclerview = new Recyclerview (context);
AddView (Mheaderview);
AddView (Mrecyclerview);
Mlayoutmanager = new Linearlayoutmanager (context);
Mlayoutmanager = new Staggeredgridlayoutmanager (2, staggeredgridlayoutmanager.vertical);
Mrecyclerview.setlayoutmanager (Mlayoutmanager);
Set item increment, remove default animation mrecyclerview.setitemanimator (new Defaultitemanimator ());
Mrecyclerview.addonscrolllistener (Onscrolllistener);
Mrecyclerview.sethasfixedsize (TRUE); Mrecyclerview.setlAyoutparams (params); } void Addchildview (context Contex) {Viewgroup.layoutparams params = new Viewgroup.layoutparams (layoutparams.match_
PARENT, layoutparams.match_parent);
Mheaderview = new Elizabethview (context);
Mrecyclerview = new Recyclerview (context);
AddView (Mheaderview);
AddView (Mrecyclerview);
Mlayoutmanager = new Linearlayoutmanager (context);
Mlayoutmanager = new Staggeredgridlayoutmanager (2, staggeredgridlayoutmanager.vertical);
Mrecyclerview.setlayoutmanager (Mlayoutmanager);
Set item increment, remove default animation mrecyclerview.setitemanimator (new Defaultitemanimator ());
Mrecyclerview.addonscrolllistener (Onscrolllistener);
Mrecyclerview.sethasfixedsize (TRUE);
Mrecyclerview.setlayoutparams (params);
/** * Shield Recyclerview Touch Event (when the drop is refreshed) * * float lasty; @Override public boolean onintercepttouchevent (Motionevent ev) {final int action = motioneventcompat.getactionmasked (EV
); Switch (action) {Case MotionEvent.ACTION_DOWN:lastY = Ev.getrawy (), break, Case MotionEvent.ACTION_UP:case motionevent. ACTion_cancel:return false;
Case MotionEvent.ACTION_MOVE:if (Mhasrefresh && mistop && ev.getrawy () > Lasty) return true;
Break
return false;
float OffsetY = 0; @Override public boolean ontouchevent (Motionevent event) {switch (event.getaction ()) {case MotionEvent.ACTION_MOVE:off Sety = Math.Abs (Event.getrawy ()-lasty);
The y difference absolute value if (OffsetY > 0) scrolltooffset (OffsetY);
else {mistop = false;} break; Case MotionEvent.ACTION_UP:if (getscrolly () <= 0) {Dorefresh (); Mheaderview.stopanim (); Mheaderview.startanim ();} E
LSE complete ();
Break
Return Super.ontouchevent (event); /** * Scroll This view hand slide position * * @param offsetY Y-axis offset/void Scrolltooffset (float OffsetY) {//If you are refreshing and now the scrolly is the same as the initial value, the representative
Benie starts refreshing and executes only once if (getscrolly () = = Mfristscollery && mrecyclerchangelistener!= null)
Mrecyclerchangelistener.startrefresh ();
int value = Math.Round (offsety/2.0f);
value = Mfristscollery-value;
Scrollto (0, value); /** * Performs a refresh operation and moves to the location where header just came out * * VOID Dorefresh () {mstatus = status_refresh; int currenty = getscrolly (); Mscroller.startscroll (0, CurrentY, 0, (mFristScoll
Ery-mheadviewheight)-currenty);
Invalidate ();
if (Mrecyclerchangelistener!= null) Mrecyclerchangelistener.onrefresh ();
Handler.sendemptymessagedelayed (Msg_refresh_complete, delay_refresh_complete); Handler Handler = new Handler () {@Override public void handlemessage (message msg) {super.handlemessage (msg); if (MSG.W hat = = Msg_load_complete) {View Footview = Madapter.getfootview (); if (Footview!= null) Mrecyclerview.smoothscrollby (0,
-footview.getmeasuredheight ());
else if (msg.what = = Msg_refresh_complete) COMPLETE ();
}
}; /** * Header returns completely hidden/public void complete () {mcurrentpage = default_min_pageindex;//the current page restore default value if (mfootviewtips != null) Mfootviewtips.settext (context.getstring (r.string.loading));//change foot prompt is loading the IF (Mrecyclerchangelistener!=
NULL) Mrecyclerchangelistener.refreshcomplete ();
Mstatus = Status_normal; int currenty = GetscrollY ();
Mscroller.startscroll (0, currenty, 0, Mfristscollery-currenty);
Mheaderview.stopanim ();
Invalidate (); @Override protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {int width = measurespec.getsize (widthm
EASURESPEC);
int height = 0; for (int i = 0; i < Getchildcount (); i++) {View child = Getchildat (i); Measurechild (Child, Widthmeasurespec, Heightmea
SURESPEC);
Height + = child.getmeasuredheight ();
} setmeasureddimension (width, height); @Override protected void OnLayout (Boolean changed, int l, int t, int r, int b) {int left = Getpaddingleft (); int top =
Getpaddingtop (); for (int i = 0; i < Getchildcount (); i++) {View child = Getchildat (i); if (i = = 0) {//center int HeaderLeft when header
Getmeasuredwidth ()/2-child.getmeasuredwidth ()/2;
Child.layout (HeaderLeft, top, HeaderLeft + child.getmeasuredwidth (), Top + child.getmeasuredheight ());
Else Child.layout (left, top, left + child.getmeasuredwidth (), Top + child.getmeasuredheight ()); top = child.Getmeasuredheight ();
} mheadviewheight = Getpaddingtop () + mheaderview.getmeasuredheight ();
Scrollto (0, mheadviewheight);//move below header to display Recyleview mfristscollery = getscrolly (); /** * Recyclerview Sliding Monitor Event * * Recyclerview.onscrolllistener Onscrolllistener = new Recyclerview.onscrolllistener () {@Ov Erride public void onscrollstatechanged (Recyclerview recyclerview, int newstate) {super.onscrollstatechanged (
Recyclerview, newstate); if (newstate = = Recyclerview.scroll_state_idle) {//slide to top if (Mfirstvisibleitem = 0) {Mistop = true;} else {mistop =
False if (mstatus!= status_load && mshowfootvisible && mlastvisibleitem + 1 = madapter.getitemcount ()) {if (m) CurrentPage = = mmaxpage) {//When the current page is the last page mfootviewtips = (TextView) Madapter.getfootview (). Findviewbyid (R.id.footer_
TIPS);
Mfootviewtips.settext (context.getstring (r.string.last_page_tips));
Handler.sendemptymessagedelayed (Msg_load_complete, delay_load_complete); else {mstatus = status_load; if (MrecyclerchangElistener!= null) {Mrecyclerchangelistener.onloadmore (); mcurrentpage++;}} @Override public void onscrolled (recyclerview recyclerview, int dx, int dy) {super.onscrolled (Recyclerview, DX, D
y); if (Mlayoutmanager instanceof linearlayoutmanager) {Mlastvisibleitem = ((Linearlayoutmanager) mLayoutManager).
Findlastvisibleitemposition ();
Mfirstvisibleitem = ((Linearlayoutmanager) mlayoutmanager). Findfirstcompletelyvisibleitemposition ();
Setfootviewvisible (); else if (Mlayoutmanager instanceof gridlayoutmanager) {Mlastvisibleitem = ((Gridlayoutmanager) mlayoutmanager).
Findlastvisibleitemposition ();
Mfirstvisibleitem = ((Gridlayoutmanager) mlayoutmanager). Findfirstcompletelyvisibleitemposition ();
Setfootviewvisible (); else if (Mlayoutmanager instanceof Staggeredgridlayoutmanager) {//
Because the specificity of the Staggeredgridlayoutmanager may cause the last item to be displayed in more than one, so here is an array to get the array, and then to the array position the maximum value is the last displayed position value. int[] lastpositions = new int[((Staggeredgridlayoutmanager) mlayoutmanager). GetspancoUNT ()];
((Staggeredgridlayoutmanager) mlayoutmanager). Findlastvisibleitempositions (lastpositions);
Mlastvisibleitem = Findmax (lastpositions); Mfirstvisibleitem = ((Staggeredgridlayoutmanager) mlayoutmanager). Findfirstvisibleitempositions (LastPositions) [0]
;
Setfootviewvisible ();
}
}
}; void Setfootviewvisible () {//When a pull load feature is set but the first page entry is not sufficient to fill recyclerview hide footer if (mhasfooter && Mfirstvisibleitem = = 0) {/** * here plus a mshowfootvisible that takes effect when the pull load feature is enabled, and never controls the number of item quantities that are not covered by the height of the * Recyclerview the time hidden Footview, Show */if (Mlastvisibleitem + 1 = madapter.getitemcount ()) {mshowfootvisible = false;} If the item quantity exceeds the view height) mshowfoot
Visible = true;
Notifydatasetchanged (); } private int Findmax (int[] positions) {int max = positions[0]; for (int value:positions) {if (value > Max) {max
= value;
} return max; Private class Adapterwrapper extends Recyclerview.adapter {private static final int type_item = 0; private static final
int type_footer = 1;
Private Recyclerview.adapter Madapter; PRivate context Mcontext;
View footer; Public Adapterwrapper (context context, Recyclerview.adapter wrappedadapter) {this.mcontext = context; This.madapter = WR
Appedadapter; @Override public Recyclerview.viewholder Oncreateviewholder (viewgroup parent, int viewtype) {Recyclerview.viewholder
Holder = null; Switch (viewtype) {Case Type_item:holder = Madapter.oncreateviewholder (parent, ViewType);
R = Layoutinflater.from (Mcontext). Inflate (R.layout.lib_recyle_footview, NULL);
LinearLayout linearlayout= (linearlayout) Footer.findviewbyid (r.id.loading_layout);
Staggeredgridlayoutmanager.layoutparams layoutparams = new Staggeredgridlayoutmanager.layoutparams (
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Layoutparams.setfullspan (TRUE);
Linearlayout.setlayoutparams (Layoutparams);
Holder = new Footerviewholder (footer);
Break
return holder; Public View Getfootview () {return footer} @Override the public void Onbindviewholder (recycleRview.viewholder holder, int position) {if (!mhasfooter | | position + 1!= getitemcount ()) {Madapter.onbindviewholder (ho
Lder, position);
@Override public int GetItemCount () {return mshowfootvisible madapter.getitemcount () + 1:madapter.getitemcount ();
@Override public int Getitemviewtype (int position) {if (mshowfootvisible && position + 1 = getitemcount ()) {
return type_footer;
else {return type_item;}} Private class Footerviewholder extends Recyclerview.viewholder {public ProgressBar ProgressBar, public TextView Tvloadin
G
Public LinearLayout llyloading; Public Footerviewholder (View Itemview) {super (Itemview); ProgressBar = (ProgressBar) Itemview.findviewbyid (
r.id.progress_loading);
tvloading = (TextView) Itemview.findviewbyid (r.id.footer_tips);
llyloading = (linearlayout) Itemview.findviewbyid (r.id.loading_layout); }
}
}
}
The
Finally has another code that is adapter:
Package Com.krain.srecyclerview.srecyclerview;
Import Android.support.v7.widget.RecyclerView;
Import Android.view.View;
Import Android.view.ViewGroup; Public abstract class BASERECYCLERVIEWADAPTER<VH extends recyclerview.viewholder> extends Recyclerview.adapter <VH> {private Onitemclicklisener mitemlistener @Override public VH oncreateviewholder (viewgroup parent, int VIEWT
ype) {View view = Getitemview (ViewType, parent);
VH VH = Getviewholder (view);
View.setonclicklistener (New Onrecycleradapterclicklistener (VH, viewtype));
View.setonlongclicklistener (New Onrecycleradapterclicklistener (VH, viewtype));
return VH;
Public abstract VH Getviewholder (View itemview);
/** * Return Item View * * @return * * Public abstract view Getitemview (int viewtype, viewgroup parent); /** * Returns adapter per ITEMN data optional/public Object getitem (int position) {return null;}/** * Item Click event Interface * * @param mitemlist Ener */public void Setonitemlistener (Onitemclicklisener mitemlistener) {This.mitemlistener =Mitemlistener;
@Override public abstract void Onbindviewholder (VH holder, int position);
@Override public abstract int getitemcount (); Class Onrecycleradapterclicklistener implements View.onclicklistener, View.onlongclicklistener {VH viewholder; int
ViewType; Public Onrecycleradapterclicklistener (VH viewholder, int viewtype) {this.viewholder = Viewholder; this.viewtype = ViewTy
Pe @Override public void OnClick (View v) {if (Mitemlistener!= null && viewholder.getadapterposition ()!= Recycler
view.no_position) {Mitemlistener.onitemclick (Viewholder.getadapterposition (), ViewType, Viewholder, v);} @Override public boolean Onlongclick (View v) {if (Mitemlistener!= null && viewholder.getadapterposition ()!= Rec
yclerview.no_position) {Mitemlistener.onitemlongclick (Viewholder.getadapterposition (), ViewType, Viewholder, V);
return false; }
}
}
Need to pay attention to a ha:
If you want to change the layout of Reciview in this modification
void Addchildview (Context Contex) {
viewgroup.layoutparams params = new Viewgroup.layoutparams (layoutparams.match _parent, layoutparams.match_parent);
Mheaderview = new Elizabethview (context);
Mrecyclerview = new Recyclerview (context);
AddView (Mheaderview);
AddView (Mrecyclerview);
Mlayoutmanager = new Linearlayoutmanager (context);
Mlayoutmanager = new Staggeredgridlayoutmanager (2, staggeredgridlayoutmanager.vertical);
Mrecyclerview.setlayoutmanager (Mlayoutmanager);
Set item increment, remove default animation
mrecyclerview.setitemanimator (New Defaultitemanimator ());
Mrecyclerview.addonscrolllistener (Onscrolllistener);
Mrecyclerview.sethasfixedsize (true);
Mrecyclerview.setlayoutparams (params);
}
Mlayoutmanager = new Staggeredgridlayoutmanager (2, staggeredgridlayoutmanager.vertical); this line is changed to the corresponding, It's not packaged in a couple of days.
Also need to pay attention to a HA is in the sliding judgment is not the last line, if it is a waterfall should be careful to judge the way and other different,
if (Mlayoutmanager instanceof Staggeredgridlayoutmanager) {
// Because the specificity of the Staggeredgridlayoutmanager may result in more than one item in the last display, an array is taken here
When you get this array and then fetch the position value in the array, the position value is the last displayed
int[] lastpositions = new int[((Staggeredgridlayoutmanager) Mlayoutmanager). Getspancount ()];
((Staggeredgridlayoutmanager) mlayoutmanager). Findlastvisibleitempositions (lastpositions);
Mlastvisibleitem = Findmax (lastpositions);
Mfirstvisibleitem = ((Staggeredgridlayoutmanager) mlayoutmanager). Findfirstvisibleitempositions (LastPositions) [0] ;
Setfootviewvisible ();
}
Because the specificity of the Staggeredgridlayoutmanager may result in multiple of the last item shown, so here is an array, Get this array and then fetch the position value in the array is the last displayed position value, then set the last line to load more display.
The above is a small series to introduce the Android Recyclerview on the pull load more and the Drop-down Refresh function implementation method, hope to help everyone, if you have any questions welcome to my message, small series will promptly reply to everyone, here also thank you for the cloud Habitat Community Web site support!