J'essaie de masquer mon FloatingActionButton fabLocation
par programme avec:
fabLocation.setVisibility(View.GONE)
mais ça ne marche pas.
Si j'ajoute Android:visibility="gone"
dans ma disposition XML, fabLocation
est masqué lorsque j'exécute mon activité, mais il réapparaît lorsque je fais défiler.
Voici ma mise en page:
<?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:id="@+id/main_content"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true">
<Android.support.design.widget.AppBarLayout
Android:id="@+id/appbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:fitsSystemWindows="true"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<Android.support.design.widget.CollapsingToolbarLayout
Android:id="@+id/collapsing_toolbar"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
app:contentScrim="@color/colorOverlay"
app:expandedTitleMarginEnd="64dp"
app:expandedTitleMarginStart="48dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
Android:id="@+id/img_couverture"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
Android:scaleType="centerCrop"
Android:src="@drawable/bg_navigation_drawer_header"
app:layout_collapseMode="parallax" />
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</Android.support.design.widget.CollapsingToolbarLayout>
</Android.support.design.widget.AppBarLayout>
<Android.support.v4.widget.NestedScrollView
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="vertical">
<Android.support.v7.widget.CardView
Android:layout_marginTop="8dp"
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:orientation="vertical"
Android:padding="16dp">
<TextView
Android:id="@+id/tv_name"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:textSize="18sp" />
<View
Android:background="@drawable/separator_orange_gradient"
Android:layout_marginTop="8dp"
Android:layout_marginBottom="16dp"
Android:layout_width="match_parent"
Android:layout_height="2dp"/>
<TextView
Android:id="@+id/tv_history"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:textAppearance="@style/TextAppearance.RobotoLight" />
</LinearLayout>
</Android.support.v7.widget.CardView>
</LinearLayout>
</Android.support.v4.widget.NestedScrollView>
<Android.support.design.widget.FloatingActionButton
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_margin="16dp"
Android:clickable="true"
Android:id="@+id/fab_location"
Android:src="@drawable/ic_fab_location_24dp"
app:backgroundTint="@color/colorOrange"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|right|end" />
Cela est dû à l'attribut app:layout_anchor
. Vous devez vous débarrasser de l'ancre avant de modifier la visibilité:
CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
p.setAnchorId(View.NO_ID);
fab.setLayoutParams(p);
fab.setVisibility(View.GONE);
Les boutons FloatingAction ancrés à AppBarLayouts ont une relation spéciale dans laquelle leur visibilité est contrôlée par la position de défilement de AppBarLayout.
Vous pouvez désactiver ceci via l'attribut behavior_autoHide
:
<Android.support.design.widget.FloatingActionButton
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
app:layout_anchor="..."
app:behavior_autoHide="false"/>
Vous pouvez également le faire par programme si vous le souhaitez:
FloatingActionButton.Behavior b
= (FloatingActionButton.Behavior) fab.getBehavior();
b.setAutoHideEnabled(false);
Si vous voulez montrer un FAB caché
<Android.support.design.widget.CoordinatorLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:id="@+id/coordinator"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true">
<Android.support.design.widget.AppBarLayout
Android:id="@+id/appbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
Android:fitsSystemWindows="true">
...
</Android.support.design.widget.AppBarLayout>
...
<Android.support.design.widget.FloatingActionButton
Android:id="@+id/fab"
Android:visibility="gone"
Android:layout_height="wrap_content"
Android:layout_width="wrap_content"
Android:clickable="true"/>
</Android.support.design.widget.CoordinatorLayout>
et
CoordinatorLayout.LayoutParams p = new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.WRAP_CONTENT, CoordinatorLayout.LayoutParams.WRAP_CONTENT);
p.anchorGravity = Gravity.BOTTOM | Gravity.END;
p.setAnchorId(R.id.appbar);
p.setMargins(...);
fab.setLayoutParams(p);
fab.setVisibility(View.VISIBLE);
Je n'étais complètement satisfait d'aucune des solutions publiées. Certains travaillaient seulement une partie du temps, alors que d'autres ne travaillaient que pour fab.setVisibility()
. Bien que je sache que c’est techniquement ce que la question initiale posait, quelques réponses ont exprimé un intérêt pour l’utilisation de fab.hide()
, et se moquer des paramètres de mise en page n’arrive pas exactement à la racine du problème.
Comme l'a souligné @ChrisBanes, le FloatingActionButton.Behavior
étant lié à la AppBarLayout
est la cause du problème. Donc, comme pour sa réponse, vous devez setAutoHideEnabled(false)
pour désactiver cette fonctionnalité. Mais cette solution n’aide en rien si vous souhaitez que la variable FloatingActionButton
se cache automatiquement et lorsque vous appelez hide()
manuellement.
Donc, pour faire ceci; Je désactive simplement la fonctionnalité de masquage automatique avant de masquer manuellement la Button
, puis la réactiver après avoir affiché manuellement la Button
:
private void hideFloatingActionButton(FloatingActionButton fab) {
CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) fab.getLayoutParams();
FloatingActionButton.Behavior behavior =
(FloatingActionButton.Behavior) params.getBehavior();
if (behavior != null) {
behavior.setAutoHideEnabled(false);
}
fab.hide();
}
private void showFloatingActionButton(FloatingActionButton fab) {
fab.show();
CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) fab.getLayoutParams();
FloatingActionButton.Behavior behavior =
(FloatingActionButton.Behavior) params.getBehavior();
if (behavior != null) {
behavior.setAutoHideEnabled(true);
}
}
FloatingActionButton layers = (FloatingActionButton) findViewById(R.id.layers);
layers.hide();
Cela fonctionne pour moi, setVisibility
ne fonctionne pas pour FloatingActionButton
car il appartient à une autre viewGroup
qui n'a pas de méthode setVisibility
.
Après quelques réponses, j'ai trouvé la solution à mon problème (même si la fab est cachée, elle peut gérer l'action!).
Tout d'abord, je vous suggère de remplacer .setVisibility(View.GONE)
et .setVisibility(View.VISIBLE)
par les méthodes .show()
et .hide()
. Ces derniers manipulent aussi actionMode
.
Le deuxième problème pour moi était l'action également gérée lorsque la fab était cachée. Pour résoudre ceci, je l'ai faite:
final CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams)floatingActionButton.getLayoutParams();
if (show){
p.setAnchorId(R.id.appBarLayout);
p.width = CoordinatorLayout.LayoutParams.WRAP_CONTENT;
p.height = CoordinatorLayout.LayoutParams.WRAP_CONTENT;
floatingActionButton.setLayoutParams(p);
floatingActionButton.show();
}else{
p.setAnchorId(View.NO_ID);
p.width = 0;
p.height = 0;
floatingActionButton.setLayoutParams(p);
floatingActionButton.hide();
}
La vraie solution à votre problème est de sous-classer la valeur par défaut FloatingActionButton.Behavior
pour appeler setAutoHide(false)
dans leurs constructeurs, afin que vous puissiez le contrôler vous-même.
Notez que je parle des feuilles du bas ci-dessous, mais c'est exactement le même problème pour tous les boutons d'action flottants ancrés, et cela répond à la question et devrait résoudre le problème comme prévu.
Sinon, vous pouvez remplacer la méthode boolean onDependentViewChanged(…)
de votre comportement personnalisé, copier la méthode statique isBottomSheet(…)
présente dans la classe FloatingActionButton.Behavior
et appeler et renvoyer uniquement la valeur de la super méthode si ce n'est pas une feuille de fond.
Vous pouvez personnaliser davantage le comportement par défaut de cette manière ou en étendant directement la classe Vanilla CoordinatorLayout.Behavior
. Vous pouvez également sélectionner le code à copier pour copier-coller à partir de la classe FloatingActionButton.Behavior
si nécessaire.
Voici le code que j'ai utilisé pour contrôler la visibilité de FAB:
/**
* Allows controlling the FAB visibility manually.
*/
@SuppressWarnings("unused")
public class FabManualHideBehavior extends FloatingActionButton.Behavior {
public FabManualHideBehavior() {
super();
setAutoHideEnabled(false);
}
public FabManualHideBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
setAutoHideEnabled(false);
}
}
Et je l'ai appliqué à mon FAB en XML de cette façon:
<Android.support.design.widget.CoordinatorLayout
...>
...
<Android.support.design.widget.FloatingActionButton
...
app:layout_anchor="@+id/bottom_sheet"
app:layout_anchorGravity="top|end"
app:layout_behavior="your.package.name.ui.behavior.FabManualHideBehavior"/>
</Android.support.design.widget.CoordinatorLayout>
Aucune de ces solutions ne m'a aidé à 100%. J'avais besoin de montrer et de masquer de manière répétée et animée (comme FAB.show()
et hide()
) tout en étant ancré à la barre d'applications lorsqu'il était visible.
J'ai fini par créer le nouveau FAB à chaque fois que je le montrais, l'insérant et le fixant manuellement, et l'animant en fonction de l'implémentation de la bibliothèque de support. C'est dégueulasse, mais ça fonctionne parfaitement.
private void hidePlayButton(final FloatingActionButton fab) {
// Cancel any animation from the default behavior
fab.animate().cancel();
fab.animate()
.scaleX(0f)
.scaleY(0f)
.alpha(0f)
.setDuration(200)
.setInterpolator(new FastOutLinearInInterpolator())
.setListener(new Animator.AnimatorListener() {
@Override public void onAnimationStart(Animator animation) {}
@Override public void onAnimationEnd(Animator animation) {
coordinatorLayout.removeView(fab);
}
@Override public void onAnimationCancel(Animator animation) {}
@Override public void onAnimationRepeat(Animator animation) {}
});
}
private void showPlayButton() {
int fabSize = getResources().getDimensionPixelSize(R.dimen.fab_size);
int margin = getResources().getDimensionPixelSize(R.dimen.fab_margin);
final FloatingActionButton fab = new FloatingActionButton(getActivity());
fab.setBackgroundTintList(ColorStateList.valueOf(ContextCompat.getColor(getActivity(), R.color.tint)));
fab.setImageDrawable(ContextCompat.getDrawable(getActivity(), R.drawable.play));
CoordinatorLayout.LayoutParams p = new CoordinatorLayout.LayoutParams(fabSize, fabSize);
p.rightMargin = p.leftMargin = p.bottomMargin = p.topMargin = margin;
p.anchorGravity = Gravity.BOTTOM | Gravity.END;
p.setAnchorId(R.id.appbar);
fab.setLayoutParams(p);
// Start from 1 pixel
fab.setAlpha(0f);
fab.setScaleX(0f);
fab.setScaleY(0f);
binding.coordinatorLayout.addView(fab);
fab.animate()
.alpha(1f)
.scaleX(1f)
.scaleY(1f)
.setDuration(200)
.setInterpolator(new FastOutLinearInInterpolator());
fab.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
hidePlayButton(fab);
// do action
}
});
}
Si vous utilisez ce code:
boolean mFabShouldBeShown;
FloatingActionButton.OnVisibilityChangedListener fabListener = new FloatingActionButton.OnVisibilityChangedListener() {
@Override
public void onShown(FloatingActionButton fab) {
super.onShown(fab);
if(!mFabShouldBeShown){
fab.hide();
}
}
@Override
public void onHidden(FloatingActionButton fab) {
super.onHidden(fab);
if(mFabShouldBeShown){
fab.show();
}
}
};
public void methodWhereFabIsHidden() {
mFabShouldBeShown = false;
mFloatingActionButton.hide(fabListener);
}
public void methodWhereFabIsShown() {
mFabShouldBeShown = true;
mFloatingActionButton.show(fabListener);
}
Si vous voulez cacher la fab, vous pouvez essayer ceci: Fab.hide ();
sinon essayez fab.show ();
prendre plaisir.
J'ai corrigé le problème show ()/hide () en plaçant le FAB dans ou hors de l'écran à l'aide des marges du modèle. Exemple:
CoordinatorLayout.LayoutParams p =
new CoordinatorLayout.LayoutParams(
CoordinatorLayout.LayoutParams.WRAP_CONTENT,
CoordinatorLayout.LayoutParams.WRAP_CONTENT);
p.gravity = Gravity.BOTTOM | Gravity.LEFT;
int fabMargin = (int)res.getDimension(R.dimen.fab_margin);
if( enabled ) {
p.setMargins(fabMargin,0,0,fabMargin);
}
else {
p.setMargins(-200,0,0,fabMargin);
}
mFab.setLayoutParams(p);
Code simple:
public static void setVisibilityFab(FloatingActionButton fab, int visibility)
{
CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
p.setAnchorId(View.NO_ID);
fab.setLayoutParams(p);
if(visibility==View.GONE || visibility==View.INVISIBLE)
fab.setVisibility(View.GONE);
else
fab.setVisibility(View.VISIBLE);
}
Je sais que votre réponse porte sur la façon de le faire fonctionner pour gone
visibilité, mais si vous utilisez invisible
à la place, vous ne vous inquiétez pas de cela et consomme moins de code.
voici une solution simple
private var fabAnchorId: Int = View.NO_ID
private val fabParams: CoordinatorLayout.LayoutParams
get() = (fab.layoutParams as CoordinatorLayout.LayoutParams)
fun showFab() {
fabParams.anchorId = fabAnchorId
fabParams.gravity = Gravity.NO_GRAVITY
fab.show()
}
fun hideFab() {
fabParams.anchorId = View.NO_ID
fabParams.gravity = Gravity.END.or(Gravity.BOTTOM)
fab.hide()
}
avant de montrer/cacher nous devons changer l'ancre et la gravité