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()
ThreePaneLayout
left
middle
right
hideLeft()
left
middle
hideLeft()
right
middle
アニメーションには次の 2 つがあります。
- a を使用して、ハードウェア レイヤーを使用して
ViewPropertyAnimator
、 の幅で 3 つのウィジェットを左に移動します。left
ObjectAnimator
のカスタム疑似プロパティでを使用して、開始時の幅を の元の幅にmiddleWidth
変更します。middle
left
(これらすべてにAnimatorSet
andを使用する方が良い考えである可能性がありますが、これは今のところ機能します)ObjectAnimators
middleWidth
ObjectAnimator
(かなり継続的な無効化が必要なため、ハードウェア層の値を無効にすることも可能です)
(アニメーションの理解にまだギャップがあり、括弧内のステートメントが好きな可能性は間違いなくあります)
最終的な効果はleft
、画面からmiddle
滑り落ち、 の元の位置とサイズにスライドし、 のすぐ後ろに移動することleft
です。right
middle
showLeft()
方向を逆にしただけで、同じアニメーターの組み合わせで、プロセスを逆にするだけです。
アクティビティは を使用して、ウィジェットThreePaneLayout
のペアと を保持します。左のフラグメントで何かを選択すると、中央のフラグメントが追加 (または内容が更新) されます。中央のフラグメントで何かを選択すると、 のキャプションが設定され、さらに が実行されます。左側を非表示にした場合、BACK を押すと実行されます。それ以外の場合、BACK はアクティビティを終了します。これはアニメーションに影響を与えるために使用されないため、その「バック スタック」を自分で管理することになります。ListFragment
Button
Button
hideLeft()
ThreePaneLayout
showLeft()
FragmentTransactions
上記のリンク先のプロジェクトは、ネイティブ フラグメントとネイティブ アニメーター フレームワークを使用しています。アニメーションに Android サポート フラグメント バックポートとNineOldAndroidsを使用する同じプロジェクトの別のバージョンがあります。
https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC
バックポートは第 1 世代の Kindle Fire で問題なく動作しますが、ハードウェアの仕様が低く、ハードウェア アクセラレーションがサポートされていないため、アニメーションは少しぎくしゃくしています。どちらの実装も、Nexus 7 やその他の現世代のタブレットではスムーズに見えます。
私は確かに、このソリューションを改善する方法、またはここで行ったこと (または @weakwire を使用したこと) よりも明確な利点を提供する他のソリューションのアイデアに対してオープンです。
貢献してくれたすべての人にもう一度感謝します!