web-dev-qa-db-fra.com

Comment déplacer une vue au-dessus de la barre Snack, tout comme un bouton flottant

J'ai une mise en page linéaire que je veux modifier lorsqu'un Snackbar apparaît.

J'ai vu beaucoup d'exemples sur la manière de faire cela avec Floating Button, mais qu'en est-il d'une vue normale?

34
Ilya Gazman

Vous devez ajouter un comportement à votre LinearLayout et l'intégrer à un CoordinatorLayout. Vous pouvez lire ceci: http://alisonhuang-blog.logdown.com/posts/290009-design-support-library-coordinator-layout-and-behavior

12
ligi

Je vais élaborer sur la réponse approuvée parce que je pense que la mise en œuvre est légèrement plus simple que celle fournie dans cet article.

Je n'ai pas réussi à trouver un comportement intégré qui gère un déplacement générique de vues, mais celui-ci est une bonne option d'usage général (from http://alisonhuang-blog.logdown.com/posts/290009-design -support-library-coordinator-layout-and-behavior lié dans un autre commentaire):

import Android.content.Context;
import Android.support.annotation.Keep;
import Android.support.design.widget.CoordinatorLayout;
import Android.support.design.widget.Snackbar;
import Android.support.v4.view.ViewCompat;
import Android.util.AttributeSet;
import Android.view.View;

@Keep
public class MoveUpwardBehavior extends CoordinatorLayout.Behavior<View> {

    public MoveUpwardBehavior() {
        super();
    }

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

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency instanceof Snackbar.SnackbarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());
        ViewCompat.setTranslationY(child, translationY);
        return true;
    }

    //you need this when you swipe the snackbar(thanx to ubuntudroid's comment)
    @Override
    public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
        ViewCompat.animate(child).translationY(0).start();
    }
}

puis, dans votre fichier de mise en page, ajoutez un comportement de mise en page comme ci-dessous:

<LinearLayout
    Android:id="@+id/main_content"
    Android:orientation="vertical"
    app:layout_behavior="com.example.MoveUpwardBehavior"/>

où layout_behavior est le chemin complet de votre comportement personnalisé. Il n'est pas nécessaire de sous-classer LinearLayout sauf si vous avez un besoin spécifique d'avoir un comportement par défaut, ce qui semble inhabituel.

63
Travis Castillo

Basé sur la réponse de @Travis Castillo. Problèmes résolus tels que:

Moving entire layout up and cause the objects on top of view disappear.
Doesnt Push the layout up when showing SnackBars immediately after eachother.

Donc, voici le code fixe pour MoveUpwardBehavior Class: 

import Android.content.Context;
import Android.support.annotation.Keep;
import Android.support.design.widget.CoordinatorLayout;
import Android.support.design.widget.Snackbar;
import Android.support.v4.view.ViewCompat;
import Android.util.AttributeSet;
import Android.view.View;

@Keep
public class MoveUpwardBehavior extends CoordinatorLayout.Behavior<View> {

    public MoveUpwardBehavior() {

        super();

    }

    public MoveUpwardBehavior(Context context, AttributeSet attrs) {

        super(context, attrs);

    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {

        return dependency instanceof Snackbar.SnackbarLayout;

    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {

        float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());

        //Dismiss last SnackBar immediately to prevent from conflict when showing SnackBars immediately after eachother
        ViewCompat.animate(child).cancel();

        //Move entire child layout up that causes objects on top disappear
        ViewCompat.setTranslationY(child, translationY);

        //Set top padding to child layout to reappear missing objects
        //If you had set padding to child in xml, then you have to set them here by <child.getPaddingLeft(), ...>
        child.setPadding(0, -Math.round(translationY), 0, 0);

        return true;
    }

    @Override
    public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {

        //Reset paddings and translationY to its default
        child.setPadding(0, 0, 0, 0);
        ViewCompat.animate(child).translationY(0).start();

    }
}

Ce code augmente ce que l’utilisateur voit à l’écran. En outre, il a accès à tous les objets de votre mise en page lorsque SnackBar est affiché.

Si vous voulez que la barre Snack recouvre les objets au lieu de pousser et que l'utilisateur ait accès à tous les objets, vous devez changer de méthode onDependentViewChanged:

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {

    float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());

    //Dismiss last SnackBar immediately to prevent from conflict when showing SnackBars immediately after eachother
    ViewCompat.animate(child).cancel();

    //Padding from bottom instead pushing top and padding from top.
    //If you had set padding to child in xml, then you have to set them here by <child.getPaddingLeft(), ...>
    child.setPadding(0, 0, 0, -Math.round(translationY));

    return true;
}

et méthode onDependentViewRemoved:

@Override
public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {

    //Reset paddings and translationY to its default
    child.setPadding(0, 0, 0, 0);

}

Malheureusement, vous perdrez l'animation lorsque l'utilisateur effectuera un balayage pour supprimer SnackBar. Et vous devez utiliser la classe ValueAnimator pour créer une animation pour les modifications de remplissage qui crée un conflit ici et vous devez les déboguer.

https://developer.Android.com/reference/Android/animation/ValueAnimator.html

Tout commentaire sur l'animation pour glisser pour supprimer SnackBar apprécié.

Si vous pouvez ignorer cette animation, vous pouvez l'utiliser.

Quoi qu'il en soit, je recommande d'abord le type.

12
IR AGCOM

J'ai implémenté cela et trouvé que lorsque la barre de menu a disparu, la vue est restée avec un espace blanc dans l'emplacement des barres, apparemment si les animations ont été désactivées sur l'appareil.

Pour résoudre ce problème, j'ai modifié la méthode onDependentViewChanged afin de stocker la position Y initiale de la vue à laquelle ce comportement est associé. Puis, lors du retrait du snack-bar, réinitialisez la position de cette vue sur la position Y enregistrée.

private static float initialPositionY;

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
    initialPositionY = child.getY();
    float translationY = Math.min(0, dependency.getTranslationY() - dependency.getHeight());
    child.setTranslationY(translationY);
    return true;
}

@Override
public void onDependentViewRemoved(CoordinatorLayout parent, View child, View dependency) {
    super.onDependentViewRemoved(parent, child, dependency);
    child.setTranslationY(initialPositionY);
}
3
Charles Barter

En plus de la réponse de Travis Castillo: Pour autoriser le déclenchement de SnackBars consécutives, dans onDependentViewChanged(), vous devez annuler toute animation en cours éventuellement lancée par onDependentViewRemoved():

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
    float translationY = Math.min(0, ViewCompat.getTranslationY(dependency) - dependency.getHeight());
    ViewCompat.animate(child).cancel(); //cancel potential animation started in onDependentViewRemoved()
    ViewCompat.setTranslationY(child, translationY);
    return true;
}

Sans annuler, LinearLayout sautera au-dessous de la 2e barre de casse-croûte quand une casse-croûte est remplacée par une autre.

1
Tromse

J'ai écrit une bibliothèque dans laquelle des vues supplémentaires peuvent être ajoutées pour animer avec le SnackProgressBar. Il comprend également progressBar et d'autres éléments. Essayez-le https://github.com/tingyik90/snackprogressbar

Supposons que vous ayez les vues suivantes à animer.

View[] views = {view1, view2, view3};

Créez une instance de SnackProgressBarManager dans votre activité et incluez la vue à animer.

SnackProgressBarManager snackProgressBarManager = new SnackProgressBarManager(rootView)
        .setViewsToMove(views)

Lorsqu'un objet SnackProgressBar est affiché ou rejeté, ces vues sont animées en conséquence.

0
tingyik90