Android – FAB para ocultar al navegar entre diferentes fragmentos en un viewpager
Estoy tratando de hacer algo muy simple.
Quisiera que el FAB aparezca solamente en una lengüeta en mi TabLayout y sea ocultado al navegar a otra lengüeta. Por ejemplo, una pestaña le permitiría agregar nuevos elementos en la FAB, pero la siguiente pestaña no le permitiría agregar elementos.
- Botón de acción flotante que no se muestra sobre la vista de reciclaje (que se encuentra dentro de un DrawerLayout)
- Android: Crear un botón de acción flotante más grande con un icono más grande
- 25.1.0 La librería de soporte de Android está rompiendo el comportamiento fabuloso
- Android: cambiar dinámicamente el icono FAB (botón de acción flotante) del código
- Cómo cambiar el diseño de android biblioteca de soporte FAB Button color de la frontera?
He seguido el diseño de diseño XML típico:
<?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/container" xmlns:tools="http://schemas.android.com/tools" > <android.support.design.widget.AppBarLayout android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|enterAlways"> <LinearLayout android:id="@+id/search_container" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical" android:orientation="horizontal"> <EditText android:id="@+id/search_view" android:layout_width="0dp" android:layout_height="?attr/actionBarSize" android:layout_weight="1" android:background="@android:color/transparent" android:gravity="center_vertical" android:hint="Search" android:imeOptions="actionSearch" android:inputType="text" android:maxLines="1" android:paddingLeft="2dp" android:singleLine="true" android:textColor="#ffffff" android:textColorHint="#b3ffffff" /> <ImageView android:id="@+id/search_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:paddingLeft="16dp" android:paddingRight="16dp" android:src="@drawable/ic_action_cancel" /> </LinearLayout> </android.support.v7.widget.Toolbar> <android.support.design.widget.TabLayout android:id="@+id/sliding_tabs" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/colorPrimary" app:tabMode="scrollable" /> </android.support.design.widget.AppBarLayout> <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="com.example.simon.behaviours.PatchedScrollingViewBehavior"/> <android.support.design.widget.FloatingActionButton android:id="@+id/fab" app:borderWidth="0dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_action_new" android:layout_margin="16dp" android:layout_gravity="bottom|right" app:layout_anchor="@+id/viewPager" app:layout_anchorGravity="bottom|right|end" app:layout_behavior="com.example.simon.behaviours.ScrollingFABBehavior" android:visibility="gone" app:fabSize="normal"> </android.support.design.widget.FloatingActionButton> </android.support.design.widget.CoordinatorLayout>
He utilizado el comportamiento siguiente para el FAB. Esto resulta en cualquier desplazamiento ascendente para hacer que el FAB desaparezca y volverá a la pantalla en un downscroll:
public class ScrollingFABBehavior extends FloatingActionButton.Behavior { private int toolbarHeight; public ScrollingFABBehavior(Context context, AttributeSet attrs) { super(); this.toolbarHeight = getToolbarHeight(context); } @Override public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionButton fab, View dependency) { return super.layoutDependsOn(parent, fab, dependency) || (dependency instanceof AppBarLayout); } @Override public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton fab, View dependency) { boolean returnValue = super.onDependentViewChanged(parent, fab, dependency); if (dependency instanceof AppBarLayout) { CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) fab.getLayoutParams(); int fabBottomMargin = lp.bottomMargin; int distanceToScroll = fab.getHeight() + fabBottomMargin; float ratio = (float)dependency.getY()/(float)toolbarHeight; fab.setTranslationY(-distanceToScroll * ratio); } return returnValue; } public static int getToolbarHeight(Context context) { final TypedArray styledAttributes = context.getTheme().obtainStyledAttributes( new int[]{R.attr.actionBarSize}); int toolbarHeight = (int) styledAttributes.getDimension(0, 0); styledAttributes.recycle(); return toolbarHeight; } }
He añadido un viewpager addOnPageChangeListener:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (position == 0) { FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab); floatingActionButton.setVisibility(View.VISIBLE); } else { FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab); floatingActionButton.setVisibility(View.GONE); } } @Override public void onPageScrollStateChanged(int state) { } });
Sólo quiero que el FAB aparezca en la primera página y desaparezca en todas las demás páginas.
El código funciona, pero cuando deslizo hacia abajo en la página siguiente, el FAB aparece después de que la visibilidad se ha establecido. Creo que tiene algo que ver con el comportamiento establecido para el FAB. ¿Alguien sabe por qué el FAB todavía se hacen visibles en un golpe hacia abajo si la visibilidad está configurada para desaparecer?
- Diseño de Android
- Biblioteca de soporte de diseño de Android
- El botón de acción flotante no sube cuando la barra de Snack está mostrando en android
- Android No se puede anclar el botón FAB a BottomSheet
- Botón de acción flotante Ser un cuadrado
- Recyclerview exterior no recibe eventos de desplazamiento de Recyclerview interno
- Android L FAB Botón sombra
- Diseño de soporte para Android elevación del botón de acción flotante no visible para los colores distintos del blanco
Esto no terminó siendo algo que quiero implementar en mi aplicación, pero me las arreglé para encontrar una respuesta al final, con algo de ayuda al mirar a través de cómo se implementó lo mismo en la aplicación wordpress.
En la aplicación wordpress, vemos un botón de acción flotante en la primera página de la aplicación que desaparece si desliza a cualquiera de las otras páginas del viewpager:
Lo hicieron a través del siguiente código: este es el código de la actividad que contiene el viewpager. Puede ver la parte relevante del código bajo el método onPageScrolled que contiene el eventbus que publica un evento cada vez que se desplaza la página. El evento sólo contiene una variable denominada positionOffset que es un valor entero de 0 a 1. Si se desplaza y la página está a medio camino entre los dos viewpagers, el positionOffset es 0.5, se obtiene la idea:
WPMainActivity.java
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { AppPrefs.setMainTabIndex(position); switch (position) { case WPMainTabAdapter.TAB_NOTIFS: new UpdateLastSeenTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; } trackLastVisibleTab(position); } @Override public void onPageScrollStateChanged(int state) { // noop } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { // fire event if the "My Site" page is being scrolled so the fragment can // animate its fab to match if (position == WPMainTabAdapter.TAB_MY_SITE) { EventBus.getDefault().post(new MainViewPagerScrolled(positionOffset)); } } });
El evento se recoge en el fragmento que contiene el código siguiente. El evento desencadena el método translationY que anima la FAB verticalmente cuando se desplaza la página según la distancia que la página se desplaza fuera de la vista determinada por la posición de Offset:
MySiteFragment
/* * animate the fab as the users scrolls the "My Site" page in the main activity's ViewPager */ @SuppressWarnings("unused") public void onEventMainThread(CoreEvents.MainViewPagerScrolled event) { mFabView.setTranslationY(mFabTargetYTranslation * event.mXOffset); }
Por último, el diseño en el archivo my_site_fragment.xml muestra que el FAB se coloca realmente en los fragmentos xml en lugar de la actividad xml.
<!-- this coordinator is only here due to https://code.google.com/p/android/issues/detail?id=175330 --> <android.support.design.widget.CoordinatorLayout android:id="@+id/coordinator" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.FloatingActionButton android:id="@+id/fab_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" android:layout_marginBottom="@dimen/fab_margin" android:layout_marginRight="@dimen/fab_margin" android:src="@drawable/gridicon_create_light" app:borderWidth="0dp" app:rippleColor="@color/fab_pressed" /> </android.support.design.widget.CoordinatorLayout>
Oye, yo tenía exactamente el mismo problema que tú.
Encontré dos métodos que trabajaron para mí.
Método 1:
Agregue un indicador estático en su MainActivity: public static boolean fabVisible;
.
Me di cuenta de que tiene un oyente para su viewPager
para detectar la página fragmento actual, por lo que puede agregar esto:
public void onPageSelected(int position) { switch (position) { case 0: fabVisible = true; mFloatingActionButton.show(); break; default: fabVisible = false; mFloatingActionButton.hide(); break; } }
Y dentro de su comportamiento fabuloso personalizado, agregue el código siguiente:
if (dyConsunmed > 0 && child.getVisibility() == View.VISIBLE ) { child.hide(); } else if (dyConsunmed < 0 && child.getVisibility() != View.VISIBLE && MainActivity.fabVisible) { child.show(); }
El punto de este método es asegurarse de que el fab debe ser visible antes de implementar el método hide & show.
Método 2:
No necesitas añadir ninguna bandera como "fabVisible" en tu MainActivity
. Aunque este método requiere que configure viewPager
como estático en MainActivity
, porque necesitamos poder acceder a él en nuestra clase de comportamiento fabulosa personalizada.
En su clase ScrollAwareFABBehavior
, agregue el código siguiente:
if (MainActivity.viewPager.getCurrentItem() == 0) { if (dyConsunmed > 0 && child.getVisibility() == View.VISIBLE ) { child.hide(); } else if (dyConsunmed < 0 && child.getVisibility() != View.VISIBLE) { child.show(); } }
El punto clave de este método, es sólo para hacer el show y ocultar el método cuando estás dentro del fragmento que desea (en mi caso es el fragmento uno por lo que el currenItem == 0). Por supuesto, con el fin de eliminar el fab en el segundo fragmento, todavía tiene que ocultarlo dentro de su oyente viewPager.
Si todavía te sientes confundido acerca del implemento, no dudes en consultar mi repositorio en GitHub y jugar con el código. La dirección es: https://github.com/Anthonyeef/FanfouDaily
Aunque el contenido del feed es todo en chino, el código está todo en inglés.
Puede hacerlo mediante programación cuando pase a la siguiente pestaña.
FloatingActionButton fab = (FloatingActionButton) view.findViewByID(R.id.fab) fab.setVisibility(View.GONE);
A continuación, establezca la visibilidad en View.VISIBLE
cuando retroceda.
Cree un booleano estático en su actividad (consulte YourActivity.isFABinCurrentTabVisible
continuación) y modifíquelo desde ViewPager, en consecuencia si debe haber un fab en la pestaña actual o no. Podría ser una solución sucia aunque … Y considerar el uso de fab.show()
y fab.hide()
lugar de setVisiblity()
. Estas realizan las animaciones de fade-in y fade-out.
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior { public ScrollAwareFABBehavior(Context context, AttributeSet attrs) { super(); } @Override public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, final View directTargetChild, final View target, final int nestedScrollAxes) { // Ensure we react to vertical scrolling return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); } @Override public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, final View target, final int dxConsumed, final int dyConsumed, final int dxUnconsumed, final int dyUnconsumed) { super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) { // User scrolled down and the FAB is currently visible -> hide the FAB child.hide(); } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE && YourActivity.isFABinCurrentTabVisible) { // User scrolled up and the FAB is currently not visible -> show the FAB child.show(); } } }
Implementar ViewPager.onPageListener y sobre paseo onPageSelected y mostrar u ocultar FAB en Tabs como por sus requisitos siguientes es el código de ejemplo:
@Override public void onPageSelected(int position) { //FAB_PAGE is the index of the page on which you want to show FAB if(position == FAB_PAGE) { fab.setVisibility(View.VISIBLE); } else { fab.setVisibility(View.GONE); } }
También puede utilizar fab.show (); Y fab.hide ();
También compruebe esto para más detalles.
Suena como si estuvieras acercándote desde el ángulo equivocado …
Por ejemplo, una pestaña le permitiría agregar nuevos elementos en la FAB, pero la siguiente pestaña no le permitiría agregar elementos.
Coloque el FAB en el Fragment
de la primera página en lugar del Fragment
/ Activity
. De esa manera desaparecerá automáticamente junto con el fragmento de la primera página – incluso se animará junto a él. También será donde pertenece, ya que no está en absoluto relacionado con las otras páginas / pestañas.
Si realmente necesita manejar el evento de clic en su Fragment
/ Activity
, haga que su fragmento de la primera página vuelva a llamar al Fragment
/ Activity
cuando se produzca ese clic.
- ¿Enfoque para la fijación de NoClassDefFoundError?
- ¿Qué hacen setDither, setFilterBitmap y setAntiAlias en una lona?