web-dev-qa-db-fra.com

À l'aide de Google Design Library, comment masquer le bouton FAB sur Défilement vers le bas?

Google a publié la bibliothèque de conception, j'utilise

 compile 'com.Android.support:design:22.2.1'

Cependant, je ne peux pas voir d'exemples de code sur la façon d'utiliser cette bibliothèque et d'animer la barre FAB en défilement. Je suppose que je peux écouter les événements de défilement sur le ListView puis animer le bouton moi-même, mais ce n'est pas intégré dans l'API (n'est-ce pas le but de cette bibliothèque de support).

Y a-t-il des exemples pour cela?

38
drlobo

Si vous utilisez RecyclerView et que vous cherchez quelque chose de simple, vous pouvez essayer ceci:

    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener(){
        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy){
            if (dy > 0)
                fabAddNew.hide();
            else if (dy < 0)
                fabAddNew.show();
        }
    });

En remplaçant 0 avec une constante, vous pouvez régler la sensibilité du déclenchement, offrant une expérience plus fluide

93
tochkov

Faire réagir un composant aux événements de défilement se fait le plus facilement avec un CoordinatorLayout.Behavior personnalisé, car ils reçoivent automatiquement les événements de défilement lorsque vous remplacez onStartNestedScroll () .

Un exemple de comportement qui masque et affiche le FAB sur le défilement trouvé dans ce FABAwareScrollingViewBehavior , construit au-dessus de cheesesquare :

public class FABAwareScrollingViewBehavior
    extends AppBarLayout.ScrollingViewBehavior {
  public FABAwareScrollingViewBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override
  public boolean layoutDependsOn(CoordinatorLayout parent,
      View child, View dependency) {
    return super.layoutDependsOn(parent, child, dependency) ||
            dependency instanceof FloatingActionButton;
  }

  @Override
  public boolean onStartNestedScroll(
      final CoordinatorLayout coordinatorLayout, final View 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 View 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) {
      // User scrolled down -> hide the FAB
      List<View> dependencies = coordinatorLayout.getDependencies(child);
      for (View view : dependencies) {
        if (view instanceof FloatingActionButton) {
          ((FloatingActionButton) view).hide();
        }
      }
    } else if (dyConsumed < 0) {
      // User scrolled up -> show the FAB
      List<View> dependencies = coordinatorLayout.getDependencies(child);
      for (View view : dependencies) {
        if (view instanceof FloatingActionButton) {
          ((FloatingActionButton) view).show();
        }
      }
    }
  }
}

Où votre vue de défilement aurait app:layout_behavior="com.support.Android.designlibdemo.FABAwareScrollingViewBehavior" Au lieu de app:layout_behavior="@string/appbar_scrolling_view_behavior"

Cependant, vous pouvez remplacer hide() et show() par n'importe quelle action si vous le souhaitez. Des détails sur la façon dont cela a été fait peuvent être trouvés dans ce post et le post de suivi pour v22.2.1 et le post de suivi pour v25 .1.0 .

Notez que cela, comme tous les comportements de défilement de la bibliothèque de conception, nécessite que votre vue prenne en charge le défilement imbriqué, ce qui vous limite actuellement à NestedScrollView , RecyclerView - ListView et ScrollView ne fonctionnent que sur les appareils API21 +.

45
ianhanniballake

Si vous êtes NE PAS en utilisant un RecycleView (c'est-à-dire, juste régulier ScrollView) Ça fera l'affaire:

mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            if (mScrollView.getScrollY() > oldScrollYPostion) {
                fab.hide();
            } else if (mScrollView.getScrollY() < oldScrollYPostion || mScrollView.getScrollY() <= 0) {
                fab.show();
            }
            oldScrollYPostion = mScrollView.getScrollY();
        }
    });

N'oubliez pas de déclarer:

private int oldScrollYPostion = 0;

à l'intérieur de votre classe.

8
BelfDev

Utiliser CoordinatorLayout est le meilleur moyen. Cependant, si vous souhaitez attacher un écouteur à ListView ou RecyclerView, vous pouvez également le faire. Je pense que c'est plus personnalisable. Voici mon exemple sur git hub.

Projet Github: Masquer FAB (bibliothèque de matériaux) avec listview

enter image description here

2
febaisi

Le @ianhanniballake fonctionne bien mais les méthodes onStartNestedScroll() et onNestedScroll() étaient obsolètes. Voici la version mise à jour:

public class FabAwareScrollingViewBehavior extends AppBarLayout.ScrollingViewBehavior {

    public FabAwareScrollingViewBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return super.layoutDependsOn(parent, child, dependency) ||
                dependency instanceof FloatingActionButton;
    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                       @NonNull View child, @NonNull View directTargetChild,
                                       @NonNull View target, int axes, int type) {
        // Ensure we react to vertical scrolling
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL ||
                super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
    }

    @Override
    public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
                                  @NonNull View child, @NonNull View target, int dx, int dy,
                                  @NonNull int[] consumed, int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);

        if (dy > 0) {
            // User scrolled down -> hide the FAB
            List<View> dependencies = coordinatorLayout.getDependencies(child);
            for (View view : dependencies) {
                if (view instanceof FloatingActionButton) {
                    ((FloatingActionButton) view).hide();
                }
            }
        } else if (dy < 0) {
            // User scrolled up -> show the FAB
            List<View> dependencies = coordinatorLayout.getDependencies(child);
            for (View view : dependencies) {
                if (view instanceof FloatingActionButton) {
                    ((FloatingActionButton) view).show();
                }
            }
        }
    }
}

Il y a aussi un très bon article de @ianhanniballake sur ce sujet: Tout intercepter avec des comportements de coordinateur

2
vovahost
recyclerView.setOnFlingListener(new RecyclerView.OnFlingListener() {
    @Override
    public boolean onFling(int velocityX, int velocityY) {
        if (velocityY < 0)
            mScrollCallbacks.showUI();
            //Code to hide the UI, I have  a custom one that slides down the nav  bar and the fab
        else if (velocityY > 0)
            mScrollCallbacks.hideUI();
            //Code to show the UI

        return false;
    }
});

Cela fonctionne très bien

2
MicroRJ