OK、質問のコメントでの@Christopherの提案に従って、Email AOSPアプリから派生した私自身のソリューションを次に示します。
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePane
@weakwire のソリューションは私のものを連想させますが、彼はAnimationアニメーターではなくクラシックを使用し、RelativeLayoutルールを使用してポジショニングを強制します。報奨金の観点からは、他の誰かがより洗練されたソリューションをまだ回答していない限り、彼はおそらく報奨金を受け取るでしょう.
一言で言えば、ThreePaneLayoutそのプロジェクトの はLinearLayoutサブクラスであり、3 つの子を持つランドスケープで動作するように設計されています。これらの子の幅は、任意の方法でレイアウト XML に設定できます。ここでは重みを使用して示していますが、ディメンション リソースなどによって特定の幅を設定することもできます。3 番目の子 (問題の Fragment C) の幅は 0 にする必要があります。
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;
}
}
ただし、実行時に、最初に幅をどのように設定したとしても、フラグメント A および B と呼ばれる質問の表示からフラグメント B および C への切り替えThreePaneLayoutに初めて使用するときに、幅の管理が引き継がれます。 -- フラグメントとの特定の関係はありません -- 3 つの部分は、、およびです。を呼び出した時点で、 とのサイズを記録し、3 つのうちのいずれかで使用された重みをゼロにするので、サイズを完全に制御できます。の時点で、 のサイズをの元のサイズに設定します。hideLeft()ThreePaneLayoutleftmiddlerighthideLeft()leftmiddlehideLeft()rightmiddle
アニメーションには次の 2 つがあります。
- a を使用して、ハードウェア レイヤーを使用して
ViewPropertyAnimator、 の幅で 3 つのウィジェットを左に移動します。left
ObjectAnimatorのカスタム疑似プロパティでを使用して、開始時の幅を の元の幅にmiddleWidth変更します。middleleft
(これらすべてにAnimatorSetandを使用する方が良い考えである可能性がありますが、これは今のところ機能します)ObjectAnimators
middleWidth ObjectAnimator(かなり継続的な無効化が必要なため、ハードウェア層の値を無効にすることも可能です)
(アニメーションの理解にまだギャップがあり、括弧内のステートメントが好きな可能性は間違いなくあります)
最終的な効果はleft、画面からmiddle滑り落ち、 の元の位置とサイズにスライドし、 のすぐ後ろに移動することleftです。rightmiddle
showLeft()方向を逆にしただけで、同じアニメーターの組み合わせで、プロセスを逆にするだけです。
アクティビティは を使用して、ウィジェットThreePaneLayoutのペアと を保持します。左のフラグメントで何かを選択すると、中央のフラグメントが追加 (または内容が更新) されます。中央のフラグメントで何かを選択すると、 のキャプションが設定され、さらに が実行されます。左側を非表示にした場合、BACK を押すと実行されます。それ以外の場合、BACK はアクティビティを終了します。これはアニメーションに影響を与えるために使用されないため、その「バック スタック」を自分で管理することになります。ListFragmentButtonButtonhideLeft()ThreePaneLayoutshowLeft()FragmentTransactions
上記のリンク先のプロジェクトは、ネイティブ フラグメントとネイティブ アニメーター フレームワークを使用しています。アニメーションに Android サポート フラグメント バックポートとNineOldAndroidsを使用する同じプロジェクトの別のバージョンがあります。
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC
バックポートは第 1 世代の Kindle Fire で問題なく動作しますが、ハードウェアの仕様が低く、ハードウェア アクセラレーションがサポートされていないため、アニメーションは少しぎくしゃくしています。どちらの実装も、Nexus 7 やその他の現世代のタブレットではスムーズに見えます。
私は確かに、このソリューションを改善する方法、またはここで行ったこと (または @weakwire を使用したこと) よりも明確な利点を提供する他のソリューションのアイデアに対してオープンです。
貢献してくれたすべての人にもう一度感謝します!