web-dev-qa-db-fra.com

Comment animer Android Fragment de l'architecture de navigation en glissant sur un ancien fragment?

Dans l'exemple d'action de navigation défini dans le graphique de navigation:

<action
    Android:id="@+id/action_fragment1_to_fragment2"
    app:destination="@id/fragment2"
    app:enterAnim="@anim/right_slide_in"
    app:popExitAnim="@anim/left_slide_out"/>

Quand Fragment2 s'ouvre et commence à glisser dans la vue de droite, Fragment1 disparaît instantanément (malheureusement). Quand Fragment2 est fermé et commence à glisser vers la droite, Fragment1 est bien visible en dessous, donnant un bel effet pop stack (comparable à iOS).

Comment puis-je conserver Fragment1 visible pendant que Fragment2 glisse en vue?

19
xinaiz

Je pense qu'en utilisant le R.anim.hold l'animation créera l'effet souhaité:

int holdingAnimation = R.anim.hold;
int inAnimation = R.anim.right_slide_in;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setCustomAnimations(inAnimation, holdingAnimation, inAnimation, holdingAnimation);
/*
... Add in your fragments and other navigation calls
*/
transaction.commit();
getSupportFragmentManager().executePendingTransactions();

Ou étiquetez-le simplement comme vous l'avez fait dans l'action.

Voici la R.anim.hold animation mentionnée ci-dessus:

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:Android="http://schemas.Android.com/apk/res/Android">
  <translate
      Android:duration="@Android:integer/config_longAnimTime"
      Android:fromYDelta="0.0%p"
      Android:toYDelta="0.0%p"/>
</set>
0
PGMacDesign

Dans mon propre cas, la solution la plus simple était d'utiliser DialogFragment avec une animation et un style appropriés.

Style:

<style name="MyDialogAnimation" parent="Animation.AppCompat.Dialog">
        <item name="Android:windowEnterAnimation">@anim/slide_in</item>
        <item name="Android:windowExitAnimation">@anim/slide_out</item>
</style>

<style name="MyDialog" parent="ThemeOverlay.MaterialComponents.Light.BottomSheetDialog">
        <item name="Android:windowIsFloating">false</item>
        <item name="Android:statusBarColor">@color/transparent</item>
        <item name="Android:windowAnimationStyle">@style/MyDialogAnimation</item>
</style>

Disposition:

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:animateLayoutChanges="true"
    Android:background="@color/colorWhite"
    Android:fillViewport="true"
    Android:fitsSystemWindows="true"
    Android:layout_gravity="bottom"
    Android:orientation="vertical"
    Android:scrollbars="none"
    Android:transitionGroup="true"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        xmlns:app="http://schemas.Android.com/apk/res-auto"
        xmlns:tools="http://schemas.Android.com/tools"
        Android:id="@+id/root_view"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent">

        // Your Ui here

    </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

Java:

public class MyFragmentDialog extends DialogFragment {
  @Nullable
  @Override
  public View onCreateView(
      @NonNull LayoutInflater inflater,
      @Nullable ViewGroup container,
      @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_dialog, container, false);
  }

  @Override
  public void onStart() {
    super.onStart();
    Dialog dialog = getDialog();
    if (dialog != null) {
      int width = ViewGroup.LayoutParams.MATCH_PARENT;
      int height = ViewGroup.LayoutParams.MATCH_PARENT;
      Objects.requireNonNull(dialog.getWindow())
          .setFlags(
              WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
              WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
      Objects.requireNonNull(dialog.getWindow()).setLayout(width, height);
      dialog.getWindow().setWindowAnimations(R.style.MyDialogAnimation);
    }
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setStyle(DialogFragment.STYLE_NORMAL, R.style.MyDialog);
  }
}
0
Jurij Pitulja

Afin d'éviter que l'ancien fragment ne disparaisse pendant l'animation coulissante du nouveau fragment, faites d'abord une animation vide composée uniquement de la durée de l'animation coulissante. Je l'appellerai @anim/stationary:

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:Android="http://schemas.Android.com/apk/res/Android"
           Android:duration="@slidingAnimationDuration" />

Ensuite, dans le graphique de navigation, définissez l'animation de sortie de l'action sur l'animation vide nouvellement créée:

    <fragment Android:id="@+id/oldFragment"
              Android:name="OldFragment">
        <action Android:id="@+id/action_oldFragment_to_newFragment"
                app:destination="@id/newFragment"
                app:enterAnim="@anim/sliding"
                app:exitAnim="@anim/stationary"
    </fragment>

L'animation de sortie est appliquée à l'ancien fragment et l'ancien fragment sera donc visible pendant toute la durée de l'animation.

Je suppose que l'ancien fragment disparaît si vous ne spécifiez pas d'animation de sortie, l'ancien fragment sera supprimé immédiatement par défaut au début de l'animation d'entrée.

0
Nickse