4

実装情報: ここで彼自身の質問に投稿された CommonsWare の応答に従って、3 ペイン レイアウトを実装しました: Gmail 3 フラグメント アニメーション シナリオの完全な作業サンプル?

一般的な考え方として、次のレベル (1 ~ 3) で構成されたレイアウトがあります。

  1. MainActivity
  2. SlidingMenu(Side Drawer UI パターン) フラグメントを左側に隠しContentFragment、3 ペイン レイアウトを格納するフラグメントとして。
  3. ContentFragment: LeftListFragment(それぞれ 3 つの TextView を含むMiddleListFragment行)、(それぞれ 8 つの TextView を含む行)の内部DetailFragment

LeftListFragment各リスト内からデータをロードするために使用しますMiddleListFragment。また、必要に応じてデータを含むカーソルを呼び出します。そのため、カスタムも実装しませんでした(この方法の方がはるかに優れた設計です)。次に、3 ペイン レイアウト + アニメーションを追加しました。動作に関しては、意図したとおりに動作し、問題はありません。時間は500msです。CursorLoadersContentProviderDetailFragmentAdaptersAnimation

問題: アニメーションが少し途切れます。いくつかのコマ落ち。Left と Middle が表示されていて、Middle リスト項目をクリックして詳細を開く場合の両方。また、[戻る] ボタンをタップして左と中央のリストをもう一度表示したとき (実際には何も読み込まれていない場合)。

私が試したこと:

  1. でフラグメントをロードするコードを削除しましたDetailView。項目をタップするだけでMiddleFragmentアニメーションが開始されますが、詳細は実際には読み込まれません。まだ吃音。また、ヒットバックすると、何もロードされず、まだスタッターが発生するため、ローダー/カーソルが原因ではないと推測されます。
  2. dumpsys gfxinfo を使用して、各フレームの計算にかかる平均時間をミリ秒単位で確認しました。実際、計算の平均時間は 18 ミリ秒であり、16 ミリ秒のしきい値を超えています。これは、アニメーション化するときに、リストを再度描画するのに時間がかかるためにスタッタリングが発生することを意味しますか? もしそうなら、なぜですか?つまり...行ビュー内に画像がまったくありません。そして、私は何も書いていないので、アダプターのコードを台無しにすることはできませんでした...
  3. Animation時間を 500ms から 200msに短縮。あなたが本当に注意深く見れば、それはまだ途切れますが、それはただ速いだけです.

編集:私は下から切り替えましrightPaneWidthleftPaneWidth(はい、それは再次元化アニメーションを削除します)、吃音はなくなりました。リストは引き続き左側にスライドしますが、幅が狭くなることはありません。吃音がなくなった場合、コードの ObjectAnimator に問題があるということですか?

ObjectAnimator.ofInt(this, "middleWidth", rightPaneWidth, leftPaneWidth)
                    .setDuration(ANIM_DURATION).start();

御時間ありがとうございます !

3 ペイン レイアウトのコード:

package com.xyz.view.widget;

import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.LinearLayout;


public class ThreePaneLayout extends LinearLayout
{
    private View leftView = null;
    private View middleView = null;
    private View rightView = null;

private static final int ANIM_DURATION = 500;
private int leftPaneWidth = -1;
private int rightPaneWidth = -1;


// -------------------------------------------------------------------------------------------
// --------------   Constructor
// -------------------------------------------------------------------------------------------


public ThreePaneLayout(Context context, AttributeSet attrs)
{
    super(context, attrs);
    setOrientation(HORIZONTAL);
}

@Override
public void onFinishInflate()
{
    super.onFinishInflate();
    leftView = getChildAt(0);
    middleView = getChildAt(1);
    rightView = getChildAt(2);
}


// -------------------------------------------------------------------------------------------
// --------------   Public methods
// -------------------------------------------------------------------------------------------


public View getLeftView()
{
    return leftView;
}

public View getMiddleView()
{
    return middleView;
}

public View getRightView()
{
    return rightView;
}

@SuppressLint("NewApi")
public void hideLeft()
{
    if (leftPaneWidth == -1)
    {

        leftPaneWidth = leftView.getWidth();
        rightPaneWidth = middleView.getWidth();
        resetWidget(leftView, leftPaneWidth);
        resetWidget(middleView, rightPaneWidth);
        resetWidget(rightView, rightPaneWidth);
        requestLayout();
    }
    translateWidgets(-1 * leftPaneWidth, leftView, middleView, rightView);
    ObjectAnimator.ofInt(this, "middleWidth", rightPaneWidth, leftPaneWidth)
                    .setDuration(ANIM_DURATION).start();
}

@SuppressLint("NewApi")
public void showLeft()
{
    translateWidgets(leftPaneWidth, leftView, middleView, rightView);
    ObjectAnimator.ofInt(this, "middleWidth", leftPaneWidth, rightPaneWidth)
                    .setDuration(ANIM_DURATION)
                    .start();
}


// -------------------------------------------------------------------------------------------
// --------------   Private methods
// -------------------------------------------------------------------------------------------


private void setMiddleWidth(int value)
{
    middleView.getLayoutParams().width = value;
    requestLayout();
}

@TargetApi(12)
private void translateWidgets(int deltaX, View... views)
{
    for (final View view : views)
    {
        ViewPropertyAnimator viewPropertyAnimator = view.animate();
        viewPropertyAnimator.translationXBy(deltaX)
                            .setDuration(ANIM_DURATION);
    }
  }

  private void resetWidget(View view, int width)
  {
      LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams();  
      layoutParams.width = width;
      layoutParams.weight = 0;
  }
}

ContentFragment の XML:

    <?xml version="1.0" encoding="utf-8"?>
<com.xyz.view.widget.ThreePaneLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_content_three_pane_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<FrameLayout
    android:id="@+id/fragment_content_framelayout_left"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="3" />

<FrameLayout
    android:id="@+id/fragment_content_framelayout_middle"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="7" />

<FrameLayout
    android:id="@+id/fragment_content_framelayout_right"
    android:layout_width="0dp"
    android:layout_height="match_parent" />
</com.xyz.view.widget.ThreePaneLayout>
4

2 に答える 2

10

問題は ObjectAnimator ではなく、アプリケーションがアニメーションのすべてのフレームで単純にやりすぎていることです。具体的には、レイアウト パラメータをアニメーション化し、すべてのフレームでレイアウトを要求しています。レイアウトは強力で便利です...しかし、最も単純なビュー階層を除いて、非常に高価になる可能性があります。アニメーション中にフレームごとにコストのかかる操作を避けることが重要であり、レイアウトはその「コストのかかる」カテゴリに分類されます。物をスライドさせるのは問題ありません (tr​​anslationX/Y)、物をフェード イン/アウトするのは良い (アルファ) ですが、実際にはすべてのフレームに物を配置しますか? いやだっていうだけだよ。

于 2013-02-08T19:33:36.103 に答える
0

ObjectAnimatorを完全に削除することになりました...もちろん、スライドアニメーションはまだありますが、同時にスムーズな再寸法化はできません。それが実際にスムーズだったというわけではありません...

とにかく、誰かがこの問題の実際の解決策を思いついた場合は、遠慮なく共有してください。ありがとう。

package com.anfuddle.view.widget;

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.LinearLayout;


public class ThreePaneLayout extends LinearLayout
{
    private View leftView = null;
    private View middleView = null;
    private View rightView = null;

private static final int ANIM_DURATION = 500;
private int rootWidth = -1;
private int leftPaneWidth = -1;
private int rightPaneWidth = -1;


// -------------------------------------------------------------------------------------------
// --------------   Constructor
// -------------------------------------------------------------------------------------------


public ThreePaneLayout(Context context, AttributeSet attrs)
{
    super(context, attrs);
    setOrientation(HORIZONTAL);
}

@Override
public void onFinishInflate()
{
    super.onFinishInflate();

    leftView = getChildAt(0);
    middleView = getChildAt(1);
    rightView = getChildAt(2);
}


// -------------------------------------------------------------------------------------------
// --------------   Public methods
// -------------------------------------------------------------------------------------------


public View getLeftView()
{
    return leftView;
}

public View getMiddleView()
{
    return middleView;
}

public View getRightView()
{
    return rightView;
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void hideLeftAndMiddle()
{
    if (leftPaneWidth == -1)
    {
        rootWidth = getWidth();
        leftPaneWidth = leftView.getWidth();
        rightPaneWidth = middleView.getWidth();
    }
    resetWidget(leftView, leftPaneWidth);
    resetWidget(middleView, rightPaneWidth);
    resetWidget(rightView, rootWidth);
    requestLayout();

    translateWidgets(-1 * rootWidth, leftView, middleView, rightView);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void hideLeft()
{
    if (leftPaneWidth == -1)
    {
        leftPaneWidth = leftView.getWidth();
        rightPaneWidth = middleView.getWidth();
    }
    resetWidget(leftView, leftPaneWidth);
    resetWidget(middleView, leftPaneWidth);
    resetWidget(rightView, rightPaneWidth);
    requestLayout();
    translateWidgets(-1 * leftPaneWidth, leftView, middleView, rightView);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void showLeftAndMiddle()
{
    translateWidgets(rootWidth, leftView, middleView, rightView);
}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void showLeft()
{
    resetWidget(leftView, leftPaneWidth);
    resetWidget(middleView, rightPaneWidth);
    resetWidget(rightView, rightPaneWidth);
    requestLayout();
    translateWidgets(leftPaneWidth, leftView, middleView, rightView);
}


// -------------------------------------------------------------------------------------------
// --------------   Private methods
// -------------------------------------------------------------------------------------------


@TargetApi(12)
private void translateWidgets(int deltaX, View... views)
{
    for (final View view : views)
    {
        ViewPropertyAnimator viewPropertyAnimator = view.animate();
        viewPropertyAnimator.translationXBy(deltaX)
                            .setDuration(ANIM_DURATION);
    }
  }

  private void resetWidget(View view, int width)
  {
      LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams();  
      layoutParams.width = width;
      layoutParams.weight = 0;
  }
}
于 2013-02-04T11:48:08.200 に答える