質問のコメントでの@Christopherの提案に従って、Email AOSPアプリから派生した私の独自のソリューションを次に示します。
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePane
@weakwireのソリューションは私のものを連想させますがAnimation、アニメーターではなくクラシックを使用し、RelativeLayoutルールを使用してポジショニングを強制します。バウンティの観点からは、より洗練されたソリューションを持つ他の誰かが回答を投稿しない限り、彼はおそらくバウンティを獲得するでしょう。
簡単に言えば、ThreePaneLayoutそのプロジェクトのはLinearLayoutサブクラスであり、3人の子供がいる風景で作業するように設計されています。これらの子の幅は、レイアウトXMLで任意の方法で設定できます-重みを使用して示していますが、ディメンションリソースなどで特定の幅を設定できます。3番目の子(問題のフラグメントC)の幅はゼロにする必要があります。
package com.commonsware.android.anim.threepane;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
public class ThreePaneLayout extends LinearLayout {
private static final int ANIM_DURATION=500;
private View left=null;
private View middle=null;
private View right=null;
private int leftWidth=-1;
private int middleWidthNormal=-1;
public ThreePaneLayout(Context context, AttributeSet attrs) {
super(context, attrs);
initSelf();
}
void initSelf() {
setOrientation(HORIZONTAL);
}
@Override
public void onFinishInflate() {
super.onFinishInflate();
left=getChildAt(0);
middle=getChildAt(1);
right=getChildAt(2);
}
public View getLeftView() {
return(left);
}
public View getMiddleView() {
return(middle);
}
public View getRightView() {
return(right);
}
public void hideLeft() {
if (leftWidth == -1) {
leftWidth=left.getWidth();
middleWidthNormal=middle.getWidth();
resetWidget(left, leftWidth);
resetWidget(middle, middleWidthNormal);
resetWidget(right, middleWidthNormal);
requestLayout();
}
translateWidgets(-1 * leftWidth, left, middle, right);
ObjectAnimator.ofInt(this, "middleWidth", middleWidthNormal,
leftWidth).setDuration(ANIM_DURATION).start();
}
public void showLeft() {
translateWidgets(leftWidth, left, middle, right);
ObjectAnimator.ofInt(this, "middleWidth", leftWidth,
middleWidthNormal).setDuration(ANIM_DURATION)
.start();
}
public void setMiddleWidth(int value) {
middle.getLayoutParams().width=value;
requestLayout();
}
private void translateWidgets(int deltaX, View... views) {
for (final View v : views) {
v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
v.animate().translationXBy(deltaX).setDuration(ANIM_DURATION)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
v.setLayerType(View.LAYER_TYPE_NONE, null);
}
});
}
}
private void resetWidget(View v, int width) {
LinearLayout.LayoutParams p=
(LinearLayout.LayoutParams)v.getLayoutParams();
p.width=width;
p.weight=0;
}
}
ただし、実行時には、幅を最初に設定した方法に関係なくThreePaneLayout、最初にを使用hideLeft()して幅の管理が引き継がれ、フラグメントAおよびBと呼ばれる質問の表示からフラグメントBおよびCへの切り替えが行われます。ThreePaneLayout-その断片には特定の関係を持っていない- 3枚がありleft、middleとright。あなたが呼ぶ時hideLeft()、私たちはの大きさを記録leftしてmiddle、我々は完全にサイズを制御することができますので、この3つの任意に使用された任意の重みをゼロ。の時点でhideLeft()、のサイズをrightの元のサイズに設定しましたmiddle。
アニメーションは2つに分かれています。
- a
ViewPropertyAnimatorを使用しleftて、ハードウェアレイヤーを使用して、3つのウィジェットをの幅で左に変換します。
- の
ObjectAnimatorカスタム疑似プロパティでmiddleWidthを使用して、middle幅を最初の幅から元の幅に変更しますleft
(これは今のところ機能しますが、これらすべてにAnimatorSetand を使用する方が良い可能性がありますObjectAnimators)
(middleWidth ObjectAnimatorハードウェアレイヤーの値を無効にすることも可能です。これは、かなり継続的な無効化を必要とするためです)
(私がアニメーションの理解にまだギャップがあること、そして括弧付きのステートメントが好きなことは間違いなく可能です)
正味の効果はつまりleft、画面の外のスライドmiddleの元の位置と大きさにスライドleftし、right右背後に変換しますmiddle。
showLeft() アニメーターの同じミックスで、方向を逆にして、単にプロセスを逆にします。
アクティビティは、ウィジェットのThreePaneLayoutペアとを保持するためにを使用しListFragmentますButton。左側のフラグメントで何かを選択すると、中央のフラグメントが追加(または内容が更新)されます。中央のフラグメントで何かを選択すると、のキャプションが設定され、でButton実行さhideLeft()れますThreePaneLayout。左側を非表示にした場合、[戻る]を押すと実行されshowLeft()ます。それ以外の場合、BACKはアクティビティを終了します。これはFragmentTransactionsアニメーションに影響を与えるために使用されないため、その「バックスタック」を自分で管理することはできません。
上記にリンクされているプロジェクトは、ネイティブフラグメントとネイティブアニメーターフレームワークを使用しています。アニメーションにAndroidサポートフラグメントバックポートとNineOldAndroidsを使用する同じプロジェクトの別のバージョンがあります。
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC
バックポートは第1世代のKindle Fireでは問題なく動作しますが、ハードウェアのスペックが低く、ハードウェアアクセラレーションがサポートされていないため、アニメーションは少しぎこちなくなります。Nexus 7や他の最新世代のタブレットでは、どちらの実装もスムーズに見えます。
このソリューションを改善する方法や、ここでやったこと(または@weakwireを使用したこと)に対して明確な利点を提供する他のソリューションのアイデアには、私は確かにオープンです。
貢献してくれた皆さん、ありがとうございました!