web-dev-qa-db-fra.com

Animer le changement de mise en page de la feuille inférieure

Dans mon application, j'utilise une feuille de fond (de la bibliothèque de support) qui fonctionne très bien. Maintenant, j'aimerais animer un changement de mise en page pendant que la feuille est déplacée vers le haut. Pour cela, j'ai créé une sous-classe de BottomSheetCallback (c'est normalement une classe interne d'un fragment, de sorte que tous les objets utilisés dans ce cals ne sont pas initialisés ici):

public class MyBehavior extends BottomSheetBehavior.BottomSheetCallback {

    Transition transition;
    float lastOffset = 0;
    Scene scene;

    public PlayerBehavior() {
        TransitionInflater inflater = TransitionInflater.from(getContext());
        transition = inflater.inflateTransition(R.transition.player);
        //transition.setDuration(300);

        scene = fullLayout;

        transition.setInterpolator(new Interpolator() {
            @Override
            public float getInterpolation(float v) {
                return lastOffset;
            }
        });
    }

    @Override
    public void onStateChanged(@NonNull View bottomSheet, int newState) {
        if(newState == BottomSheetBehavior.STATE_DRAGGING) {
            TransitionManager.go(scene, transition);
        }
    }

    @Override
    public void onSlide(View bottomSheet, final float slideOffset) {
        scene = (slideOffset > lastOffset) ? smallLayout : fullLayout;
        lastOffset = slideOffset;
    }
}

Comme vous pouvez le constater, j'ai également créé deux Scene à partir de fichiers de mise en page différents et un Transition personnalisé pour animer les scènes avec le TransitionManager. Mon problème est que la Transition devrait être basée sur le paramètre slideOffset (compris entre 0 et 1) mais la TransitionManager utilise la classe Animation en arrière-plan, qui est normalement basée sur Android.

J'ai essayé de créer l'Intapolator personnalisé mais cela ne fonctionne pas correctement. Alors, comment puis-je créer une Transition qui repose sur une variable externe et non sur le temps?

26
Cilenco

D'après votre description, je pense que vous essayez d'obtenir quelque chose comme le comportement des feuilles de fond de Google Maps. La mise en page change au fur et à mesure que vous faites glisser le bottomsheet .

Si c'est ce que vous essayez d'atteindre, vous n'avez pas besoin d'appliquer des animations personnalisées, car bottomsheetdialog possède lui-même ce comportement d'animation lorsqu'il est intégré à un parent Coordinator Layout .

Voici un exemple de code montrant comment j'implémente le même comportement. Cela rend également le FloatingActionButton invisible lorsque la feuille de fond est déplacée jusqu'à la taille de l'écran plein écran:

  1. Créez un journal de travail que vous souhaitez utiliser dans votre mise en page principale.

    public class CustomBottomDialog extends BottomSheetDialogFragment {
    
    String mSomeName;
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // if some arguments are passed from the calling activity 
        mSomeName = getArguments().getString("some_name");
    
    
    }
    
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View bottomSheet = inflater.inflate(R.layout.bottomsheet_layout, container, false);
         // initialise your bottomsheet_layout items here 
        TextView tvName = bottomSheet.findViewById(R.id.display_name);
        tvName.setText(mSomeName); 
        tvName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
               // do something here
                ((MainActivity)getActivity()).doSomething();
            }
        });
    
        return bottomSheet;
    }
    }
    
  2. bottomsheet_layout: 

    <Android.support.design.widget.CoordinatorLayout 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">
    
    <Android.support.design.widget.FloatingActionButton
    Android:id="@+id/nav"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:src="@drawable/navigation_tilt_grey"
    app:backgroundTint="@color/colorAccent"
    app:elevation="3dp"
    app:fabSize="normal"
    Android:layout_marginEnd="@dimen/activity_horizontal_margin"
    app:layout_anchor="@+id/live_dash"
    app:layout_anchorGravity="top|right" />
    
    <!--BottomSheet-->
    
    <Android.support.v4.widget.NestedScrollView
    Android:id="@+id/live_dash"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:background="#F3F3F3"
    Android:clipToPadding="true"
    app:layout_behavior="Android.support.design.widget.BottomSheetBe 
    havior"
    tools:layout_editor_absoluteY="150dp">
    
    <!--Include your items here, the height of all items combined
    will take the main screen layout size with animation-->
    
    </Android.support.v4.widget.NestedScrollView>
    
    </Android.support.design.widget.CoordinatorLayout>
    
  3. Appeler cette fiche inférieure de votre activité:

    public void notifyBottomSheet(String somename){
    
    BottomSheetDialogFragment customDialogFragment = new CustomBottomDialog();
    Bundle args = new Bundle();
    args.putString("some_name", somename);
    customDialogFragment.setArguments(args);
    customDialogFragment.show(getSupportFragmentManager(), customDialogFragment.getTag());
    customDialogFragment.setCancelable(false); // if you don't wish to hide
    }
    

    J'espère que cela résout ce que vous essayez d'atteindre.

1
Prashant Kumar
## Translation Animation ##
<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:interpolator="@Android:anim/accelerate_decelerate_interpolator"
    Android:fillAfter="true"
    >
    <translate
        Android:fromYDelta="100%p"
        Android:toYDelta="-30%p"
        Android:duration="900" />
</set>

## Activité principale ##

@Override
protected void onResume() {
    super.onResume();
    Animation am= AnimationUtils.loadAnimation(this,R.anim.fadeout);
    tv5.startAnimation(am);
    Animation myanim= AnimationUtils.loadAnimation(this,R.anim.translate);
    tv1.startAnimation(myanim);
    myanim.setStartOffset(500);
    Animation animation= AnimationUtils.loadAnimation(this,R.anim.translate);
    animation.setStartOffset(1000);
    tv2.startAnimation(animation);
    Animation an= AnimationUtils.loadAnimation(this,R.anim.translate);
    an.setStartOffset(1500);
    tv3.startAnimation(an);
    Animation ab= AnimationUtils.loadAnimation(this,R.anim.translate);
    ab.setStartOffset(2000);
    tv4.startAnimation(ab);
    Animation ac= AnimationUtils.loadAnimation(this,R.anim.fadein);
    ac.setStartOffset(2500);
    btn1.startAnimation(ac);
}
0
akshat saini

Pour faire glisser facilement quelque chose au bas de l'écran, vous pouvez utiliser un code tel que:

final int activityHeight = findViewById(Android.R.id.content).getHeight();
cardContainer.animate().yBy(activityHeight - cardContainer.getY()).setDuration(SLIDE_OUT_DURATION);

cardContainer est la vue que vous essayez de faire glisser de l'écran.

Voir cet article de blog pour l'exemple complet. Notez que vous pouvez également utiliser translationY au lieu de yBy. Une autre façon plus générique de le faire est avec ce code:

public static ViewPropertyAnimator slideOutToBottom(Context ctx, View view) {
    final int screenHeight = ctx.getResources().getDisplayMetrics().heightPixels;
    int[] coords = new int[2];
    view.getLocationOnScreen(coords);
    return view.animate().translationY(screenHeight - coords[Y_INDEX]).setDuration(SLIDE_OUT_DURATION);
}

public static ViewPropertyAnimator slideInFromBottom(Context ctx, View view) {
    final int screenHeight = ctx.getResources().getDisplayMetrics().heightPixels;
    int[] coords = new int[2];
    view.getLocationOnScreen(coords);
    view.setTranslationY(screenHeight - coords[Y_INDEX]);
    return view.animate().translationY(0).setDuration(SLIDE_IN_DURATION).setInterpolator(new OvershootInterpolator(1f));
}
0

Je ne sais pas si c'est ce que vous voulez, mais peut-être qu'au lieu d'utiliser transition, vous pouvez utiliser la fonction animate() puisqu'avec cette fonction, vous pouvez tout changer pour votre animation (heure, visibilité, etc.).

0
oumaya saratoon