studio library android material-design android-design-library floating-action-button

android - library - floating action button menu



FloatingActionButton no se oculta (12)

Código simple:

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); }

Estoy tratando de ocultar mi fabLocation FloatingActionButton fabLocation programación con:

fabLocation.setVisibility(View.GONE)

Pero no funciona.

Si agrego android:visibility="gone" en mi diseño XML, fabLocation está oculto cuando ejecuto mi actividad, pero reaparece cuando me desplazo.

Aquí está mi diseño:

<?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" />


Después de algunas respuestas, fundé la solución para mi problema (¡incluso cuando el fab está oculto puede manejar la acción!).

En primer lugar, le sugiero que reemplace .setVisibility(View.GONE) y .setVisibility(View.VISIBLE) con los métodos .show() y .hide() . Estos últimos manejan también actionMode .

El segundo problema para mí fue la acción que también se manejó cuando el fab estaba oculto, para resolver esto lo hice:

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 verdadera solución para su problema es setAutoHide(false) subclase de FloatingActionButton.Behavior predeterminado para llamar a setAutoHide(false) en sus constructores, para que pueda controlarlo usted mismo.

Tenga en cuenta que hablo de las hojas inferiores a continuación, pero es exactamente el mismo problema para todos los botones de acción flotante anclados, y responde a la pregunta y debería resolver el problema como se esperaba.

Alternativamente, puede anular el boolean onDependentViewChanged(…) desde su Comportamiento personalizado, copiar el método estático isBottomSheet(…) presente en la clase FloatingActionButton.Behavior , y solo invocar y devolver el valor del supermétodo si no es una hoja inferior .

Puede personalizar aún más el comportamiento predeterminado de esta manera, o ampliando la clase Vanilla CoordinatorLayout.Behavior directamente, y puede seleccionar el código para copiar pegar desde la clase FloatingActionButton.Behavior si es necesario.

Aquí está el código que utilicé para controlar la visibilidad de FAB:

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 } }); }

Y lo apliqué a mi FAB en xml de esta manera:

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); }


Los FloatingActionButtons anclados a AppBarLayouts tienen una relación especial donde su visibilidad está controlada por la posición de desplazamiento de AppBarLayout.

Puede desactivarlo mediante el atributo behavior_autoHide :

<android.support.design.widget.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_anchor="..." app:behavior_autoHide="false"/>

También puede hacer esto programáticamente si lo desea:

FloatingActionButton.Behavior b = (FloatingActionButton.Behavior) fab.getBehavior(); b.setAutoHideEnabled(false);


Ninguna de estas otras soluciones me ayudó al 100%. Necesitaba mostrar y ocultar repetidos y animados (como FAB.show() y hide() ) mientras estaba anclado a la barra de la aplicación cuando estaba visible.

Terminé creando el FAB nuevo cada vez que lo mostré, insertándolo y anclándolo manualmente, y animándolo según la implementación de la biblioteca de soporte. Es asqueroso, pero funciona perfectamente.

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);


No estaba completamente satisfecho con ninguna de las soluciones publicadas. Algunos solo funcionaron una parte del tiempo, mientras que otros solo funcionaron para fab.setVisibility() . Si bien sé que esto es técnicamente lo que hizo la pregunta original, algunas respuestas expresaron interés en utilizar fab.hide() , y jugar con los parámetros de diseño no llega exactamente a la raíz del problema.

Como señaló @ChrisBanes, el comportamiento de FloatingActionButton.Behavior relacionado con AppBarLayout es lo que causa el problema. Entonces, al igual que con su respuesta, debe establecer setAutoHideEnabled(false) para deshabilitar esa funcionalidad. Pero esta solución no ayuda si realmente desea que FloatingActionButton oculte automáticamente y cuando llame a hide() manualmente.

Entonces para hacer esto; Simplemente desactivo la función de ocultación automática antes de ocultar manualmente el Button , luego vuelvo a habilitar la funcionalidad después de que muestre el Button manualmente:

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); } }


Sé que tu respuesta es sobre cómo hacer que funcione para la visibilidad perdida, pero si usas invisible en su lugar, no tendrás preocupaciones sobre eso y tendrás menos código.


Se debe a la app:layout_anchor atributo app:layout_anchor . Debe deshacerse del ancla antes de cambiar la visibilidad:

CoordinatorLayout.LayoutParams p = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); p.setAnchorId(View.NO_ID); fab.setLayoutParams(p); fab.setVisibility(View.GONE);


Si quieres mostrar FAB oculto

<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>

y

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);


Trabajé alrededor de la falla de show () / hide () colocando el FAB dentro o fuera de la pantalla usando los márgenes de diseño. ejemplo:

/** * 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); } }


Yo uso este código:

<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>


aquí hay una solución 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() }

antes de mostrar / ocultar tenemos que cambiar el ancla y la gravedad