質問のコメントでの@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
(これは今のところ機能しますが、これらすべてにAnimatorSet
and を使用する方が良い可能性があります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を使用したこと)に対して明確な利点を提供する他のソリューションのアイデアには、私は確かにオープンです。
貢献してくれた皆さん、ありがとうございました!