Suspension button (Floatingactionbutton), hereinafter referred to as FAB, today we talk about some of its properties and usage, as well as resolving and resolving sdk25 above Floatingactionbutton only hide the problem that is not displayed.
Show the dynamic diagram first
This development environment is based on SDK25.
The design package should be introduced before use
Compile ' com.android.support:design:25.3.1 '
XML Properties
<android.support.design.widget.floatingactionbutton android:id= "@+id/contact_fab" Android:layout_width= "Wrap_content" android:layout_height= "wrap_content" android:layout_gravity= "Botto M|right "android:layout_margin=" 10DP "android:src=" @mipmap/ic_launcher "app:backgroundtint=" @color /gray "app:backgroundtintmode=" multiply "app:borderwidth=" 0DP "app:elevation=" @dimen/activity_hori Zontal_margin "app:fabsize=" Auto "app:pressedtranslationz=" @dimen/activity_horizontal_margin "app: Ripplecolor= "@color/gray" app:usecompatpadding= "true"/>
App:backgroundtint button background color, not set, default to use theme Coloraccent color app:backgroundtintmode button background color mode, when setting screen is a little different from other modes, Differences in color change, other unchanged, specific unknown, can be ignored app:borderwidth this property if you do not set 0DP, the Fab on the 4.1 SDK will appear as a square, and the SDK after 5.0 does not have a shadow effect. So the shadow size is set to Borderwidth= "0DP" app:elevation default state. App:fabsize set the size, which has two values, normal and Mini, corresponding to the size of 56DP and 40DP App:pressedtranslationz button pressed down the shadow size of the State App:ripplecolor Sets the background color when clicked app:usecompatpadding whether a compatible fill size is used
usage
Can be used with Floatingactionmenu or coordinatorlayout. Just take Coordinatorlayout to do the example here.
Use the Recyclerview up and down to make the fab visible or hidden, and click the fab display Snackbar
Layout
<?xml version= "1.0" encoding= "Utf-8"?> <android.support.design.widget.coordinatorlayout xmlns:android= " Http://schemas.android.com/apk/res/android "xmlns:app=" Http://schemas.android.com/apk/res-auto "Android:layout_ Width= "Match_parent" android:layout_height= "match_parent" android:orientation= "vertical" > <android.supp
Ort.v7.widget.RecyclerView android:id= "@+id/contact_recyclerview" android:layout_width= "Match_parent" android:layout_height= "Match_parent" app:layout_behavior= "@string/appbar_scrolling_view_behavior" > < ;/android.support.v7.widget.recyclerview> <android.support.design.widget.floatingactionbutton android:i D= "@+id/contact_fab" android:layout_width= "wrap_content" android:layout_height= "Wrap_content" Android Oid:layout_gravity= "Bottom|right" android:layout_margin= "10DP" android:src= "@mipmap/ic_launcher" a
pp:backgroundtint= "@color/turquoise" App:backgroundtintmode= "src_in" app:borderwidth= "0DP" app:elevation= "5DP" app:fabsize= "aut
O "app:pressedtranslationz=" 50DP "app:ripplecolor=" @color/gray "app:usecompatpadding=" true " App:layout_anchor= "@+id/contact_recyclerview" app:layout_anchorgravity= "Bottom|right|end" App:layout_beh Avior= "Com.voctex.ui.tablayout.other.ScrollingViewBehavior"/> </ Android.support.design.widget.coordinatorlayout>
Code Implementation
Recyclerview recyclerview= ((Recyclerview) Findviewbyid (R.id.contact_recyclerview));
Recyclerview.sethasfixedsize (TRUE);
Recyclerview.setitemanimator (New Defaultitemanimator ());
Set a vertical layout manager int orientation = linearlayoutmanager.vertical;
Recyclerview.setlayoutmanager (New Linearlayoutmanager (Mcontext, orientation, false));
List<string> mlist=new arraylist<> ();
for (int i = 0; i <; i++) {Mlist.add ("position:" +i);
} tablayoutadapter tablayoutadapter=new Tablayoutadapter (recyclerview,mlist);
Recyclerview.setadapter (Tablayoutadapter);
Floatingactionbutton fab= ((Floatingactionbutton) Findviewbyid (R.id.contact_fab));
Fab.setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) { Snackbar.make (V, "floatingactionbtn", Snackbar.length_short). Setaction ("Action", NEW View.onclicklistener () {@Override public void OnClick (View v) {
Vttoast.s (Mcontext, "Paladin biography");
}}). Show (); }
});
In the above code, it is only necessary to specify a property in the XML for the fab to enable the Recyclerview to display or hide the fab when it slides up or down.
App:layout_behavior= "Com.voctex.ui.tablayout.other.ScrollingViewBehavior"
The value is a custom class, inherited from Floatingactionbutton.behavior, overriding the two methods of Onstartnestedscroll and Onnestedscroll, the relevant code is as follows:
Package com.voctex.ui.tablayout.other;
Import Android.content.Context;
Import Android.support.design.widget.CoordinatorLayout;
Import Android.support.design.widget.FloatingActionButton;
Import Android.support.v4.view.ViewCompat;
Import Android.util.AttributeSet;
Import Android.view.View;
/** * Created by Mac_xihao on 17/7/3. * (~ ̄▽ ̄) ~ Well, coax. * * public class Scrollingviewbehavior extends Floatingactionbutton.behavior {/** * because it is used in XML a
Pp:layout_behavior defines this behavior statically, * you must implement a constructor to make the effect of the layout work correctly.
* Otherwise Could not inflate Behavior subclass error messages. * * @param context * @param attrs */Public Scrollingviewbehavior (context context, AttributeSet attrs)
{Super (context, attrs);
}/** * handles scrolling events in the vertical direction * * @param coordinatorlayout * @param child * @param directtargetchild * @param target * @param nestedscrollaxes * @return */@Override public boolean Onstartnesteds Croll (CoordinatorLayout Coordinatorlayout, Floatingactionbutton Child, view directtargetchild, view target, int nestedscrollaxes) {
Ensure we react to vertical scrolling return nestedscrollaxes = = Viewcompat.scroll_axis_vertical | | Super.onstartnestedscroll (coordinatorlayout, Child, Directtargetchild, Target, Nestedscroll
Axes);
}/** * Checks the position of Y and determines whether the button animates into or out * * @param coordinatorlayout * @param child * @param target * @param dxconsumed * @param dyconsumed * @param dxunconsumed * @param dyunconsumed * * @Overrid e public void Onnestedscroll (Coordinatorlayout coordinatorlayout, Floatingactionbutton Child, View target, int dxconsu Med, int dyconsumed, int dxunconsumed, int dyunconsumed) {super.onnestedscroll (coordinatorlayout, child, Target,
Dxconsumed, dyconsumed, dxunconsumed, dyunconsumed); if (dyconsumed > && child.getvisibility () = = view.visible) {//User scrolled down and the Fab is currently VISIBLE, hide the fab//execute hidden
Animation Child.hide (); } else if (Dyconsumed < -10 && child.getvisibility ()! = view.visible) {//User scrolled up and the
Fab is currently not visible, show the FAB//perform the animated display of Child.show ();
}
}
}
In fact, to here is the end of the, the implementation is very simple, but I found a test when the problem of a relatively pit, is recylerview in the sliding, can only hide, but do not show fab. Resolve and resolve sdk25 Floatingactionbutton only hidden issues that are not displayed
This problem pit ah, surfing the internet to see a lot of people are so realized, are can hide the display, I am aiming at this problem Baidu, found someone online said sdk25 above will appear not show fab problem, specific problems appear in the code:
Sdk25 above, Coordinatorlayout's Onnestedscroll method will be more than a piece of code
@Override public void Onnestedscroll (View target, int dxconsumed, int dyconsumed, int dxunconsumed, int d
yunconsumed) {final int childCount = Getchildcount ();
Boolean accepted = false;
for (int i = 0; i < ChildCount; i++) {final View view = Getchildat (i);
Sdk25 above will be more out of this judgment if (view.getvisibility () = = GONE) {//If the child is GONE, skip ...
Continue
} FINAL Layoutparams LP = (layoutparams) view.getlayoutparams ();
if (!lp.isnestedscrollaccepted ()) {continue;
} final Behavior Viewbehavior = Lp.getbehavior ();
if (viewbehavior! = null) {Viewbehavior.onnestedscroll (this, view, Target, dxconsumed, dyconsumed,
Dxunconsumed, dyunconsumed);
accepted = true; }} if (accepted) {onchildviewschanged(Event_nested_scroll); }
}
That is, coordinatorlayout when sliding, to determine whether the sub-view is set to gone, if it is, directly execute the next cycle, and then do not callback Onnestedscroll, The Onnestedscroll method of our custom class is not gone.
When Fab executes the Hide method, the default is to set the Fab to gone, and let's look at the Hide method in Fab
/**
* Hides the button.
* <p>this method would animate the button hide if the view has already been laid out.</p>
*/public
Voi D Hide () {
hide (null);
}
/**
* Hides the button.
* <p>this method would animate the button hide if the view has already been laid out.</p>
*
* @param l Istener the listener to notify if this view is hidden
*
/public void hide (@Nullable onvisibilitychangedlistene R listener) {
Hide (listener, true);
}
void Hide (@Nullable Onvisibilitychangedlistener Listener, Boolean fromuser) {
Getimpl (). Hide ( Wraponvisibilitychangedlistener (Listener), fromuser);
}
Finally, the following code is called, and Fromuser defaults to True, which is a critical value
Getimpl (). Hide (Wraponvisibilitychangedlistener (listener), fromuser);
Next we go on, Getimpl () is which object to get
Private Floatingactionbuttonimpl Getimpl () {
if (Mimpl = = null) {
Mimpl = Createimpl ();
}
return mimpl;
}
Private Floatingactionbuttonimpl Createimpl () {
final int sdk = Build.VERSION.SDK_INT;
if (SDK >=) {
return new Floatingactionbuttonlollipop (this, new Shadowdelegateimpl (),
Viewutils.default_ animator_creator);
} else if (SDK >=) {
return new Floatingactionbuttonics (this, new Shadowdelegateimpl (),
Viewutils.default _animator_creator);
} else {
return new Floatingactionbuttongingerbread (this, new Shadowdelegateimpl (),
Viewutils.default_ animator_creator);
}
}
Here we default to test with more than 4.0 of the phone, so the object is Floatingactionbuttonics instance, and then go to see how its Hide method is implemented.
@Override void Hide (@Nullable final Internalvisibilitychangedlistener Listener, final Boolean fromuser) {if (
Isorwillbehidden ()) {//We either is or would soon be hidden, skip the call return;
} mview.animate (). Cancel ();
if (Shouldanimatevisibilitychange ()) {manimstate = anim_state_hiding;
Mview.animate (). ScaleX (0f). ScaleY (0f). Alpha (0f) . Setduration (Show_hide_anim_duration). Setinterpolator (Animationutils.fast_out_linear_in_inte Rpolator). Setlistener (New Animatorlisteneradapter () {Private Boolean Mcancel
Led @Override public void Onanimationstart (Animator animation) {Mview.int
Ernalsetvisibility (view.visible, Fromuser);
mcancelled = false; } @Override public void Onanimationcancel (Animator animati
ON) {mcancelled = true;
} @Override public void Onanimationend (Animator animation) {
Manimstate = Anim_state_none; if (!mcancelled) {mview.internalsetvisibility (fromuser?)
View.GONE:View.INVISIBLE, Fromuser);
if (listener! = null) {Listener.onhidden ();
}
}
}
}); } else {//If the view isn ' t laid out, or we ' re in the editor, don ' t run the animation mview.inte Rnalsetvisibility (Fromuser?
View.GONE:View.INVISIBLE, Fromuser); if (listener! = null) {Listener.onhidden (); }
}
}
Look directly inside the Onanimationend method, the default Fromuser is true, so here fab is directly set to gone, And coordinatorlayout of the Onnestedscroll method in the loop and judge the sub-view for the gone when directly out of the execution of the next cycle, here is very contradictory.
So under what circumstances is the Fromuser false?
Because hide (@Nullable Onvisibilitychangedlistener Listener, Boolean Fromuser) method access is default, only classes within the same package can be called, I searched directly for the fab call to this method, and found that there are two other methods that call this method, namely
Private Boolean updatefabvisibilityforappbarlayout (coordinatorlayout parent, Appbarlayout Appbarlayout, Fl
Oatingactionbutton child) {if (!shouldupdatevisibility (appbarlayout, child)) {return false;
} if (mtmprect = = null) {Mtmprect = new Rect ();
}//First, let's get the visible rect of the dependency final rect rect = mtmprect;
Viewgrouputils.getdescendantrect (parent, appbarlayout, rect); if (Rect.bottom <= appbarlayout.getminimumheightforvisibleoverlappingcontent ()) {//If the anchor ' s Bo
Ttom is below the seam, we'll animate our FAB out Child.hide (Minternalautohidelistener, false); } else {//else, we ' ll animate our FAB back in Child.show (Minternalautohidelistener, F
Alse);
} return true; } Private Boolean UpdatefabviSibilityforbottomsheet (View Bottomsheet, Floatingactionbutton child) {if (!shouldupdatevisibi
Lity (Bottomsheet, child)) {return false; } coordinatorlayout.layoutparams LP = (coordinatorlayout.layoutparams) Child.getlayoutpara
MS (); if (Bottomsheet.gettop () < Child.getheight ()/2 + lp.topmargin) {child.hide (Minternalautohidelistener
, false);
} else {child.show (Minternalautohidelistener, false);
} return true;
}
Can be found that the two classes, hide method is passed false, and, from the name can be found that the two methods should be for Appbarlayout and bottomsheet, access rights are private, So we can continue to search for calls within the Fab class, and find that both methods are called together in the other two methods
@Override public Boolean ondependentviewchanged (coordinatorlayout parent, Floatingactionbutton Child, View dependency) {if (dependency instanceof appbarlayout) {//If we ' re depending on an A
Ppbarlayout we'll show/hide it automatically//if the FAB is anchored to the Appbarlayout
Updatefabvisibilityforappbarlayout (parent, (appbarlayout) dependency, child);
} else if (Isbottomsheet (dependency)) {Updatefabvisibilityforbottomsheet (dependency, child);
} return false; } @Override public Boolean onlayoutchild (coordinatorlayout parent, Floatingactionbutton Child, int LayoutDirection) {//First, let's make sure this visibility of the FAB is consistent final L
ist<view> dependencies = parent.getdependencies (child); for (int i = 0, count = dependencies.size (); I < count; i++) {
Final View dependency = Dependencies.get (i);
if (dependency instanceof appbarlayout) {if (Updatefabvisibilityforappbarlayout (
Parent, (Appbarlayout) dependency, child)} {break; }} else if (Isbottomsheet (dependency)) {if (Updatefabvisibilityforbottomsheet (Depend
Ency, Child)} {break; }}}//The coordinatorlayout lay out the FAB parent.onlayout
Child (Child, layoutdirection);
Now offset it if needed offsetifneeded (parent, child);
return true;
}
That is, only when the Appbarlayout or Bottomsheet are in the same sibling layout as the Fab, and then the fab shows and hides when they slide, what about the other layouts. How to solve this situation like Recyclerview.
Actually also very simple, as long as not to execute the Hide method on the line, their own implementation of hidden animation, I here directly took the Fab hidden animation, has been modified a bit, and then become my own, and then directly paste code good.
Inherit Floatingactionbutton.behavior, and implement a class Scrollawarefabbehavior, the code is as follows
Package com.voctex.ui.tablayout.other;
Import Android.animation.Animator;
Import Android.animation.AnimatorListenerAdapter;
Import Android.content.Context;
Import Android.support.design.widget.CoordinatorLayout;
Import Android.support.design.widget.FloatingActionButton;
Import Android.support.v4.view.ViewCompat;
Import Android.support.v4.view.animation.FastOutLinearInInterpolator;
Import Android.support.v4.view.animation.LinearOutSlowInInterpolator;
Import Android.util.AttributeSet;
Import Android.view.View;
/** * Created by Mac_xihao on 17/7/3. * (~ ̄▽ ̄) ~ Well, Coax * * public class Scrollawarefabbehavior extends Floatingactionbutton.behavior {/** * because it is in XML to make
Define static behavior with App:layout_behavior, * you must implement a constructor to make the layout work properly.
* Otherwise Could not inflate Behavior subclass error messages. * * @param context * @param attrs */Public Scrollawarefabbehavior (context context, AttributeSet attrs)
{super (); }/** * handles scrolling events in the vertical direction * * @pAram Coordinatorlayout * @param child * @param directtargetchild * @param target * @param nestedscroll
Axes * @return */@Override public boolean onstartnestedscroll (Coordinatorlayout coordinatorlayout, Floatingactionbutton Child, view directtargetchild, view target, int nestedscrollaxes)
{//Ensure we react to vertical scrolling return nestedscrollaxes = = Viewcompat.scroll_axis_vertical | | Super.onstartnestedscroll (coordinatorlayout, child, DIRECTT