web-dev-qa-db-ja.com

Android Navigation Architectureフラグメントを古いフラグメントの上をスライドするようにアニメーション化する方法は?

ナビゲーショングラフで定義されているナビゲーションアクションの例:

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

いつ Fragment2が開き、右側からビューにスライドし始めます、Fragment1は即座に(悲しいことに)消えます。いつ Fragment2は閉じており、右にスライドし始めますFragment1はその下で見やすく、ナイススタックポップ効果を与えます(iOSに匹敵)。

どうすればFragment1表示中Fragment2スライドして表示されますか?

19
xinaiz

R.anim.holdアニメーションは、必要な効果を作成します。

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();

または、アクション内のようにラベルを付けます。

こちらがR.anim.hold上記のアニメーション:

<?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

私自身の場合、最も簡単な解決策は、適切なアニメーションとスタイルでDialogFragmentを使用することでした。

スタイル:

<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>

レイアウト:

<?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

新しいフラグメントのスライドアニメーション中に古いフラグメントが消えないようにするには、最初にスライドアニメーションの継続時間のみで構成される空のアニメーションを作成します。 @anim/stationaryと呼びます:

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

次に、ナビゲーショングラフで、アクションの終了アニメーションを新しく作成した空のアニメーションに設定します。

    <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>

終了アニメーションは古いフラグメントに適用されるため、アニメーションの全期間にわたって古いフラグメントが表示されます。

古いフラグメントが消える理由についての私の推測は、exitアニメーションを指定しない場合、Enterアニメーションが始まると古いフラグメントはデフォルトですぐに削除されます。

0
Nickse