入れ子になったフラグメントが遷移アニメーション中に消える


100

ここではシナリオがあります:活動は、フラグメントが含まAターン用途では、getChildFragmentManager()フラグメントを追加するA1と、A2その中にonCreateそのように:

getChildFragmentManager()
  .beginTransaction()
  .replace(R.id.fragmentOneHolder, new FragmentA1())
  .replace(R.id.fragmentTwoHolder, new FragmentA2())
  .commit()

これまでのところ、非常に良い、すべてが期待どおりに実行されています。

次に、アクティビティで次のトランザクションを実行します。

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .replace(R.id.fragmentHolder, new FragmentB())
  .addToBackStack(null)
  .commit()

移行中、enterフラグメントのアニメーションBは正しく実行されますが、フラグメントA1とA2は完全に消えます。[戻る]ボタンでトランザクションを元に戻すと、それらは適切に初期化され、popEnterアニメーション中に正常に表示されます。

私の簡単なテストでは、奇妙になりました-子フラグメントのアニメーションを設定すると(以下を参照)、exitフラグメントを追加するとアニメーションが断続的に実行されますB

getChildFragmentManager()
  .beginTransaction()
  .setCustomAnimations(enter, exit)
  .replace(R.id.fragmentOneHolder, new FragmentA1())
  .replace(R.id.fragmentTwoHolder, new FragmentA2())
  .commit()

達成したい効果は単純です- フラグメント(anim2)のアニメーションexit(またはそれである必要がありますpopExitか?A)を実行して、ネストされた子を含むコンテナー全体をアニメーション化します。

それを達成する方法はありますか?

編集ここでテストケースを見つけてください

Edit2:静的アニメーションを試してみてくれた@StevenByleに感謝します。どうやらアニメーションごとに(トランザクション全体にグローバルではなく)アニメーションを設定できます。つまり、子は無期限の静的アニメーションセットを持つことができ、親は異なるアニメーションを持つことができ、1つのトランザクションですべてをコミットできます。 。以下の説明と更新されたテストケースプロジェクトを参照してください。


R.id.fragmentHolderA、A1、A2などに関しては何ですか?
CommonsWare 2013

fragmentHolderはアクティビティのレイアウトのidで、fragment {One、Two} HolderはフラグメントAのレイアウトにあります。3つはすべて異なります。フラグメントAは、fragmentHolderに最初に追加されました(つまり、フラグメントBがフラグメントAを置き換えています)。
Delyan 2013

ここでサンプルプロジェクトを作成しました:github.com/BurntBrunch/NestedFragmentsAnimationsTest、リポジトリにはapkも含まれています。これは本当に迷惑なバグであり、私はそれを回避する方法を探しています(それが自分のコードにない場合)。
Delyan 2013

この問題についてもう少し知っています。フラグメントが消えるのは、子が親の前にライフサイクルイベントを処理するためです。本質的に、A1とA2はAの前に削除され、アニメーションが設定されていないため、突然消えます。これを多少緩和する方法は、Aを置き換えるトランザクションでA1とA2を明示的に削除することです。これにより、終了時にアニメーション化されますが、親コンテナーもアニメーション化されているため、アニメーション速度は2乗されます。このアーティファクトを生成しないソリューションがいただければ幸いです。
Delyan 2013

質問で述べた変更(スターターフラグメントの置き換え)は、実際に実行したい変更ですか、それとも単なる例ですか?changeFragmentメソッドを1回だけ呼び出しますか?
Luksprog、2013

回答:


36

トランザクションで親フラグメントが削除または置換されたときにネストされたフラグメントがユーザーに表示されないようにするために、画面に表示された画像を提供することで、フラグメントがまだ存在していることを「シミュレート」できます。この画像はネストされたフラグメントコンテナーの背景として使用されるため、ネストされたフラグメントのビューが消えても、画像はそれらの存在をシミュレートします。また、ネストされたフラグメントのビューとの対話性が失われることは問題とは思われません。削除されている最中にユーザーにアクションを実行してほしくないからです(おそらくユーザーアクションとして)上手)。

私が作った小さな例の背景画像(基本的な何か)を設定しています。


1
それが私が最終的に使用したソリューションだったので、私はあなたに賞金を授与することにしました。お時間をいただきありがとうございます!
Delyan 2013

16
うわー、とても汚い。私たちのAndroid開発者が、いくつかの見栄えのためだけに行かなければならない

1
私は2番目のタブからビューページャーを持っています他のフラグメントを置き換えています。それを押し戻すと、ビューページャーの2番目のタブを表示する必要がありますが、開いていますが、空白のページが表示されています。上記のスレッドであなたが提案したことを試しましたが、それでも同じです。
ハリッシュ

@Harishが書いたようにユーザーが戻ってきたときに問題が残る
Ewoks

1
本気ですか?その2018とこれはまだ事ですか?:(
Archie G.Quiñones19年

69

したがって、これにはさまざまな回避策があるようですが、@ Jayd16の回答に基づいて、子フラグメントのカスタムトランジションアニメーションを可能にし、実行する必要がない、かなり確実なキャッチオールソリューションを見つけたと思いますレイアウトのビットマップキャッシュ。

BaseFragment拡張するクラスを用意しFragment、すべてのフラグメントがそのクラスを拡張するようにします(子フラグメントだけではありません)。

そのBaseFragmentクラスで、以下を追加します。

// Arbitrary value; set it to some reasonable default
private static final int DEFAULT_CHILD_ANIMATION_DURATION = 250;

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    final Fragment parent = getParentFragment();

    // Apply the workaround only if this is a child fragment, and the parent
    // is being removed.
    if (!enter && parent != null && parent.isRemoving()) {
        // This is a workaround for the bug where child fragments disappear when
        // the parent is removed (as all children are first removed from the parent)
        // See https://code.google.com/p/android/issues/detail?id=55228
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else {
        return super.onCreateAnimation(transit, enter, nextAnim);
    }
}

private static long getNextAnimationDuration(Fragment fragment, long defValue) {
    try {
        // Attempt to get the resource ID of the next animation that
        // will be applied to the given fragment.
        Field nextAnimField = Fragment.class.getDeclaredField("mNextAnim");
        nextAnimField.setAccessible(true);
        int nextAnimResource = nextAnimField.getInt(fragment);
        Animation nextAnim = AnimationUtils.loadAnimation(fragment.getActivity(), nextAnimResource);

        // ...and if it can be loaded, return that animation's duration
        return (nextAnim == null) ? defValue : nextAnim.getDuration();
    } catch (NoSuchFieldException|IllegalAccessException|Resources.NotFoundException ex) {
        Log.w(TAG, "Unable to load next animation from parent.", ex);
        return defValue;
    }
}

残念ながら、これにはリフレクションが必要です。ただし、この回避策はサポートライブラリ用であるため、サポートライブラリを更新しない限り、基盤となる実装が変更されるリスクはありません。ソースからサポートライブラリを構築する場合は、次のアニメーションリソースIDのアクセサーを追加して、Fragment.javaリフレクションの必要性をなくすことができます。

このソリューションは、親のアニメーション期間を「推測」する必要をなくし(「何もしない」アニメーションが親の終了アニメーションと同じ期間を持つようにする)、子フラグメントでカスタムアニメーションを実行できるようにします(たとえば、子フラグメントを別のアニメーションで交換します)。


5
これは私のスレッドでのお気に入りのソリューションです。ビットマップを必要とせず、子フラグメントに追加のコードを必要とせず、親から子フラグメントに情報を実際にリークしません。
jacobhyphenated 2014年

1
@EugenPechanec 子のフラグメントではなく、フラグメントのnextAnimが必要です。それがすべてのポイントです。
Kevin Coppock

1
残念ながら、このアプローチは、子フラグメントと、暗黙的に親フラグメントのメモリリークを引き起こし、Lollipopの下のAndroidバージョンでも同様です:(
Cosmin

8
この非常に便利なソリューションをありがとうございます。ただし、現在のサポートライブラリを使用するには少し更新が必要です(27.0.2、どのバージョンがこのコードを壊したかわかりません)。オブジェクトmNextAnim内になりましたmAnimationInfo。あなたはこのようにアクセスすることができます:Field animInfoField = Fragment.class.getDeclaredField("mAnimationInfo"); animInfoField.setAccessible(true); Object animationInfo = animInfoField.get(fragment); Field nextAnimField = animationInfo.getClass().getDeclaredField("mNextAnim");
デビッドLericolais

5
@DavidLericolaisは、あなたの後にさらに1行のコードを追加したいと考えています。val nextAnimResource = nextAnimField.getInt(animationInfo);行を交換するにはint nextAnimResource = nextAnimField.getInt(fragment);
tingyik90

32

私はかなりきれいな解決策を思いつくことができました。IMOは最小限のハックであり、技術的には「ビットマップを描く」ソリューションですが、少なくともフラグメントlibによって抽象化されています。

子フラグが親クラスをこれでオーバーライドすることを確認してください:

private static final Animation dummyAnimation = new AlphaAnimation(1,1);
static{
    dummyAnimation.setDuration(500);
}

@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
    if(!enter && getParentFragment() != null){
        return dummyAnimation;
    }
    return super.onCreateAnimation(transit, enter, nextAnim);
}

子フラグに終了アニメーションがある場合、点滅する代わりにアニメーション化されます。これを利用して、子フラグメントを一定期間フルアルファで単純に描画するアニメーションを作成できます。このようにして、アニメーション化しても親フラグメントに表示されたままになり、目的の動作が得られます。

私が考えることができる唯一の問題は、その期間を追跡することです。多分それを多めに設定することもできますが、そのアニメーションがまだどこかに描画されていると、パフォーマンスの問題が発生する可能性があります。


助かります、ありがとう。継続時間の値は重要ではありません
iscariot

これまでで最もクリーンなソリューション
Liran Cohen 2017

16

私は明確にするために私の解決策を投稿しています。解決策は非常に簡単です。親のフラグメントトランザクションアニメーションを模倣しようとしている場合は、同じ期間の子フラグメントトランザクションにカスタムアニメーションを追加するだけです。ああ、add()の前にカスタムアニメーションを設定してください。

getChildFragmentManager().beginTransaction()
        .setCustomAnimations(R.anim.none, R.anim.none, R.anim.none, R.anim.none)
        .add(R.id.container, nestedFragment)
        .commit();

R.anim.noneのxml(私の両親のアニメーション時間は250ミリ秒です)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="0" android:toXDelta="0" android:duration="250" />
</set>

私は非常に似たようなことをしましたが、子を更新するときに「追加」ではなく「表示」を使用しました。「getChildFragmentManager()。executePendingTransactions()」も追加しましたが、それが厳密に必要かどうかはわかりません。ただし、このソリューションは問題なく機能し、一部の提案のようにフラグメントの「画像を提供する」必要はありません。
Brian Yencho 2017年

これは素晴らしかった。ただし、子フラグメントを切り替えるときに遅延が発生していました。これを避けるために、ちょうどなしアニメーションと第二のパラメータを設定するfragmentTransaction.setCustomAnimations(R.anim.none, 0, R.anim.none, R.anim.none)
小野

7

これはあなたの問題を完全に解決できないかもしれませんが、おそらく他の人のニーズに合うかもしれません、あなたは実際にsを動かしたりアニメートしない子供にenter/ exitおよびpopEnter/ popExitアニメーションを追加できます。アニメーションが親アニメーションと同じ継続時間/オフセットを持っている限り、それらは親のアニメーションと一緒に移動/アニメーションしているように見えます。FragmentFragmentFragment


1
彼の解決策が普遍的に機能するので、私はLuksprogに賞金を与えました。私は静的なアニメーションのトリックを試しましたが(実際には期間は関係ありません-親がなくなると、ビューは明らかに消えます)、それらはすべての可能なケースで機能しませんでした(質問の下の私のコメントを参照)。また、このアプローチは抽象化をリークします。子を持つフラグメントの親は、その事実を知っており、子のアニメーションを設定するために追加の手順を実行する必要があるためです。いずれにせよ、お時間を頂き誠にありがとうございます!
Delyan 2013

これは、水密ソリューションよりも回避策であり、わずかに壊れやすいと考えられることに同意します。しかし、それは単純なケースで機能します。
Steven Byle 2013

4

子フラグメントでこれを行うことができます。

@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
    if (true) {//condition
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(getView(), "alpha", 1, 1);
        objectAnimator.setDuration(333);//time same with parent fragment's animation
        return objectAnimator;
    }
    return super.onCreateAnimator(transit, enter, nextAnim);
}

ありがとうございました!多分最善ではないかもしれませんが、おそらく最も簡単な解決策です。
Bug56

2

@@@@@@@@@@@@@@@@@@@@@@@@@@@@

編集:これには他にも問題があったため、このソリューションを実装しないことになりました。Squareは最近、フラグメントを置き換える2つのライブラリを発表しました。これは実際にはフラグメントをハックしてグーグルが望まないことをするよりも良い代替手段かもしれないと思います。

http://corner.squareup.com/2014/01/mortar-and-flow.html

@@@@@@@@@@@@@@@@@@@@@@@@@@@@

私は、この問題を将来抱える人々を助けるためにこの解決策を立てると思いました。他の人とのオリジナルのポスターの会話をたどって、彼が投稿したコードを見ると、最終的に、オリジナルのポスターが親フラグメントをアニメーション化しながら子フラグメントで何もしないアニメーションを使用するという結論に達していることがわかります。このソリューションは、すべての子フラグメントを追跡する必要があるため、理想的ではありません。これは、ViewPagerをFragmentPagerAdapterと共に使用する場合に面倒になる可能性があります。

私は至る所で子フラグメントを使用しているので、効率的でモジュール式(簡単に削除できる)のこのソリューションを思いついたので、彼らがそれを修正してこのノーオペレーションアニメーションが不要になった場合に備えます。

これを実装する方法はたくさんあります。シングルトンの使用を選択し、ChildFragmentAnimationManagerと呼びます。基本的に、親に基づいて子フラグメントを追跡し、要求されたときに何もしないアニメーションを子に適用します。

public class ChildFragmentAnimationManager {

private static ChildFragmentAnimationManager instance = null;

private Map<Fragment, List<Fragment>> fragmentMap;

private ChildFragmentAnimationManager() {
    fragmentMap = new HashMap<Fragment, List<Fragment>>();
}

public static ChildFragmentAnimationManager instance() {
    if (instance == null) {
        instance = new ChildFragmentAnimationManager();
    }
    return instance;
}

public FragmentTransaction animate(FragmentTransaction ft, Fragment parent) {
    List<Fragment> children = getChildren(parent);

    ft.setCustomAnimations(R.anim.no_anim, R.anim.no_anim, R.anim.no_anim, R.anim.no_anim);
    for (Fragment child : children) {
        ft.remove(child);
    }

    return ft;
}

public void putChild(Fragment parent, Fragment child) {
    List<Fragment> children = getChildren(parent);
    children.add(child);
}

public void removeChild(Fragment parent, Fragment child) {
    List<Fragment> children = getChildren(parent);
    children.remove(child);
}

private List<Fragment> getChildren(Fragment parent) {
    List<Fragment> children;

    if ( fragmentMap.containsKey(parent) ) {
        children = fragmentMap.get(parent);
    } else {
        children = new ArrayList<Fragment>(3);
        fragmentMap.put(parent, children);
    }

    return children;
}

}

次に、すべてのフラグメントが拡張するフラグメント(少なくとも子フラグメント)を拡張するクラスが必要です。私はすでにこのクラスを持っていて、それをBaseFragmentと呼んでいます。フラグメントビューが作成されたら、ChildFragmentAnimationManagerに追加し、破棄されたら削除します。これは、onAttach / Detach、またはシーケンス内の他のマッチング方法で行うことができます。Create / Destroy Viewを選択するための私のロジックは、フラグメントにビューがない場合、表示され続けるためにアニメーション化する必要がないためです。このアプローチは、FragmentPagerAdapterが保持しているすべてのFragmentを追跡するのではなく、3のみを追跡するため、Fragmentsを使用するViewPagersでより適切に機能するはずです。

public abstract class BaseFragment extends Fragment {

@Override
public  View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {

    Fragment parent = getParentFragment();
    if (parent != null) {
        ChildFragmentAnimationManager.instance().putChild(parent, this);
    }

    return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onDestroyView() {
    Fragment parent = getParentFragment();
    if (parent != null) {
        ChildFragmentAnimationManager.instance().removeChild(parent, this);
    }

    super.onDestroyView();
}

}

すべてのフラグメントが親フラグメントによってメモリに保存されたので、このようにそれらのアニメーションを呼び出すことができ、子フラグメントは消えません。

FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ChildFragmentAnimationManager.instance().animate(ft, ReaderFragment.this)
                    .setCustomAnimations(R.anim.up_in, R.anim.up_out, R.anim.down_in, R.anim.down_out)
                    .replace(R.id.container, f)
                    .addToBackStack(null)
                    .commit();

また、あなたがそれを持っているので、これがres / animフォルダーに入るno_anim.xmlファイルです:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator">
    <translate android:fromXDelta="0" android:toXDelta="0"
        android:duration="1000" />
</set>

繰り返しますが、このソリューションは完璧だとは思いませんが、子フラグメントがあるすべてのインスタンスよりもはるかに優れており、親フラグメントにカスタムコードを実装して各子を追跡できます。私はそこに行ったことがあり、それは面白くない。


1

Luksprogが示唆したように、現在のフラグメントをビットマップにスナップショットするよりも、この問題のより良い解決策を見つけたと思います。

トリックは、削除またはデタッチされるフラグメントを非表示にすることであり、アニメーションが完了した後にのみ、フラグメントは独自のフラグメントトランザクションで削除またはデタッチされます。

我々が持っている想像FragmentAしてFragmentB、両方のサブ断片と。今、あなたが通常行うとき:

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .add(R.id.fragmentHolder, new FragmentB())
  .remove(fragmentA)    <-------------------------------------------
  .addToBackStack(null)
  .commit()

その代わりに

getSupportFragmentManager()
  .beginTransaction()
  .setCustomAnimations(anim1, anim2, anim1, anim2)
  .add(R.id.fragmentHolder, new FragmentB())
  .hide(fragmentA)    <---------------------------------------------
  .addToBackStack(null)
  .commit()

fragmentA.removeMe = true;

次に、フラグメントの実装について:

public class BaseFragment extends Fragment {

    protected Boolean detachMe = false;
    protected Boolean removeMe = false;

    @Override
    public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
        if (nextAnim == 0) {
            if (!enter) {
                onExit();
            }

            return null;
        }

        Animation animation = AnimationUtils.loadAnimation(getActivity(), nextAnim);
        assert animation != null;

        if (!enter) {
            animation.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    onExit();
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
        }

        return animation;
    }

    private void onExit() {
        if (!detachMe && !removeMe) {
            return;
        }

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        if (detachMe) {
            fragmentTransaction.detach(this);
            detachMe = false;
        } else if (removeMe) {
            fragmentTransaction.remove(this);
            removeMe = false;
        }
        fragmentTransaction.commit();
    }
}

切り離されたフラグメントを表示しようとしているため、popBackStackはエラーを引き起こしませんか?
アレクサンドル

1

マップフラグメントで同じ問題が発生していました。含まれているフラグメントの終了アニメーション中に消え続けました。回避策は、子フラグメントのアニメーションを追加することです。これにより、親フラグメントの終了アニメーションの間、子フラグメントが表示され続けます。子フラグメントのアニメーションは、継続時間中、アルファを100%に保ちます。

アニメーション:res / animator / keep_child_fragment.xml

<?xml version="1.0" encoding="utf-8"?>    
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:propertyName="alpha"
        android:valueFrom="1.0"
        android:valueTo="1.0"
        android:duration="@integer/keep_child_fragment_animation_duration" />
</set>

マップフラグメントが親フラグメントに追加されると、アニメーションが適用されます。

親フラグメント

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.map_parent_fragment, container, false);

    MapFragment mapFragment =  MapFragment.newInstance();

    getChildFragmentManager().beginTransaction()
            .setCustomAnimations(R.animator.keep_child_fragment, 0, 0, 0)
            .add(R.id.map, mapFragment)
            .commit();

    return view;
}

最後に、子フラグメントアニメーションの継続時間はリソースファイルで設定されます。

values / integers.xml

<resources>
  <integer name="keep_child_fragment_animation_duration">500</integer>
</resources>

0

イースト化されたフラグメントの消失をアニメーション化するには、ChildFragmentManagerでスタックを強制的にポップバックできます。これにより、遷移アニメーションが起動します。これを行うには、OnBackButtonPressedイベントに追いつくか、バックスタックの変更をリッスンする必要があります。

これがコードの例です。

View.OnClickListener() {//this is from custom button but you can listen for back button pressed
            @Override
            public void onClick(View v) {
                getChildFragmentManager().popBackStack();
                //and here we can manage other fragment operations 
            }
        });

  Fragment fr = MyNeastedFragment.newInstance(product);

  getChildFragmentManager()
          .beginTransaction()
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE)
                .replace(R.neasted_fragment_container, fr)
                .addToBackStack("Neasted Fragment")
                .commit();

0

私は最近、この問題に遭遇しました:ネストされたフラグメントが正しく移行しない

ビットマップを保存したり、リフレクションやその他の不満足な方法を使用したりせずに、これを解決するソリューションがあります。

サンプルプロジェクトは、こちらで確認できます:https : //github.com/zafrani/NestedFragmentTransitions

効果のGIFは、こちらで確認できます。https//imgur.com/94AvrW4

私の例では、2つの親フラグメント間で分割された6つの子フラグメントがあります。Enter、Exit、Pop、Pushの遷移を問題なく達成できます。構成の変更とバックプレスも正常に処理されます。

ソリューションの大部分は、私のBaseFragmentの(子と親のフラグメントによって拡張されたフラグメント)のonCreateAnimator関数にあります。

   override fun onCreateAnimator(transit: Int, enter: Boolean, nextAnim: Int): Animator {
    if (isConfigChange) {
        resetStates()
        return nothingAnim()
    }

    if (parentFragment is ParentFragment) {
        if ((parentFragment as BaseFragment).isPopping) {
            return nothingAnim()
        }
    }

    if (parentFragment != null && parentFragment.isRemoving) {
        return nothingAnim()
    }

    if (enter) {
        if (isPopping) {
            resetStates()
            return pushAnim()
        }
        if (isSuppressing) {
            resetStates()
            return nothingAnim()
        }
        return enterAnim()
    }

    if (isPopping) {
        resetStates()
        return popAnim()
    }

    if (isSuppressing) {
        resetStates()
        return nothingAnim()
    }

    return exitAnim()
}

アクティビティと親フラグメントは、これらのブール値の状態を設定する責任があります。私のサンプルプロジェクトから、方法と場所を簡単に表示できます。

私の例ではサポートフラグメントを使用していませんが、同じロジックをそれらとそのonCreateAnimation関数で使用できます


0

この問題を解決する簡単な方法Fragmentは、標準ライブラリフラグメントクラスの代わりに、このライブラリのクラスを使用することです。

https://github.com/marksalpeter/contract-fragment

補足として、このパッケージにはContractFragment、親子フラグメントの関係を利用してアプリを構築するのに役立つと思われる便利なデリゲートパターンも含まれています。


0

上記の@kcoppockの答えから、

あなたがActivity-> Fragment-> Fragments(複数の積み重ね、次の助け)を持っているなら、最良の答えのIMHOを少し編集してください。

public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {

    final Fragment parent = getParentFragment();

    Fragment parentOfParent = null;

    if( parent!=null ) {
        parentOfParent = parent.getParentFragment();
    }

    if( !enter && parent != null && parentOfParent!=null && parentOfParent.isRemoving()){
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else
    if (!enter && parent != null && parent.isRemoving()) {
        // This is a workaround for the bug where child fragments disappear when
        // the parent is removed (as all children are first removed from the parent)
        // See https://code.google.com/p/android/issues/detail?id=55228
        Animation doNothingAnim = new AlphaAnimation(1, 1);
        doNothingAnim.setDuration(getNextAnimationDuration(parent, DEFAULT_CHILD_ANIMATION_DURATION));
        return doNothingAnim;
    } else {
        return super.onCreateAnimation(transit, enter, nextAnim);
    }
}

0

私の問題は親フラグメントの削除(ft.remove(fragment))で、子アニメーションは発生していませんでした。

基本的な問題は、子フラグメントがアニメーションを終了する親フラグメントの前にすぐに破棄されることです。

子フラグメントのカスタムアニメーションが親フラグメントの削除時に実行されない

他の人が回避したように、親を削除する前に親(子ではなく)を非表示にする方法があります。

            val ft = fragmentManager?.beginTransaction()
            ft?.setCustomAnimations(R.anim.enter_from_right,
                    R.anim.exit_to_right)
            if (parentFragment.isHidden()) {
                ft?.show(vehicleModule)
            } else {
                ft?.hide(vehicleModule)
            }
            ft?.commit()

親を実際に削除したい場合は、カスタムアニメーションのリスナーを設定して、アニメーションがいつ終了するかを確認する必要があります。そうすれば、親フラグメントを安全にファイナライズできます(削除)。これを行わないと、タイムリーに、アニメーションが強制終了される可能性があります。NBアニメーションは、独自の非同期キューで行われます。

ところで、子アニメーションは親アニメーションを継承するため、子フラグメントにカスタムアニメーションは必要ありません。



0

古いスレッドですが、誰かがここでつまずいた場合に備えて:

上記のアプローチはすべて私にとって非常に魅力的ではありません。ビットマップソリューションは非常に汚く、パフォーマンスが悪いです。他のものは、問題の子フラグメントを作成するために使用されるトランザクションで使用される遷移の期間を知るために子フラグメントを必要とします。私の目にもっと良い解決策は次のようなものです:

val currentFragment = supportFragmentManager.findFragmentByTag(TAG)
val transaction = supportFragmentManager
    .beginTransaction()
    .setCustomAnimations(anim1, anim2, anim1, anim2)
    .add(R.id.fragmentHolder, FragmentB(), TAG)
if (currentFragment != null) {
    transaction.hide(currentFragment).commit()
    Handler().postDelayed({
        supportFragmentManager.beginTransaction().remove(currentFragment).commit()
    }, DURATION_OF_ANIM)
} else {
    transaction.commit()
}

現在のフラグメントを非表示にして新しいフラグメントを追加するだけです。アニメーションが終了したら、古いフラグメントを削除します。この方法では、1つの場所で処理され、ビットマップは作成されません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.