3窗格布局片段动画是口吃

Bog*_*rac 4 android android-animation android-fragments objectanimator

实现信息: 我已经在他自己的问题上发布了CommonsWare响应之后实现了3个窗格布局:Gmail三片段动画场景的完整工作示例?

总的来说,我的布局包括以下级别(1到3):

  1. MainActivity
  2. SlidingMenu(侧面抽屉UI图案)片段隐藏在左侧,而一个ContentFragment片段包含3个窗格布局.
  3. 内部的ContentFragment:LeftListFragment,(每3个TextViews行)MiddleListFragment(每个8个TextViews行), DetailFragment.

LeftListFragmentMiddleListFragment用于CursorLoadersContentProvider每个列表中加载数据.DetailFragment在需要时还要求带有数据的游标.所以我甚至没有实现自定义Adapters(这种方式更好的设计).然后我添加了3个窗格布局+动画.就工作而言,它按预期工作,没有问题.Animation时间是500毫秒.

问题: 动画口吃不多.一些丢帧.当左侧和中间都可见时,我单击中间列表项以打开详细信息; 当我点击"返回"按钮再次查看左侧和中间列表(当没有实际装载时).

我尝试过的:

  1. 删除了加载片段的代码DetailView.我只是点击一个项目,MiddleFragment动画开始,没有任何细节实际加载.仍然口吃.此外,当击中,没有任何负载,它仍然口吃,所以我认为加载器/光标不是这个的原因.
  2. 我使用dumpsys gfxinfo来查看计算每帧的平均时间(以ms为单位).实际上,计算的平均时间是18ms,高于16ms阈值.这是否意味着口吃是因为在制作动画时再次绘制列表所需的时间?如果是这样,为什么?我的意思是......在行视图中我根本没有任何图像.我无法搞砸Adapters代码,因为我没有写过任何代码......
  3. Animation时间从500毫秒减少到200毫秒.如果你仔细观察它仍然是口吃,它只是更快.

编辑:我切换rightPaneWidthleftPaneWidth下面(是的,这删除了重新定尺寸的动画),口吃现在已经消失.列表仍然向左侧滑动,但宽度不会变小.因此,如果现在没有更多的口吃,这是否意味着我的代码中的ObjectAnimator存在问题?

ObjectAnimator.ofInt(this, "middleWidth", rightPaneWidth, leftPaneWidth)
                    .setDuration(ANIM_DURATION).start();
Run Code Online (Sandbox Code Playgroud)

谢谢你的时间 !

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

Che*_*ase 10

问题不是ObjectAnimator,而是你的应用程序在动画的每一帧上都做得太多了.具体来说,您可以设置布局参数的动画并在每个帧上请求布局.布局功能强大且有用......但除了最简单的视图层次结构之外,它可能非常昂贵.在动画期间避免昂贵的每帧操作非常重要,并且布局属于"昂贵"类别.滑动的东西很好(translationX/Y),淡入/淡出的东西是好的(alpha),但实际上在每一帧上放置东西?拒绝吧.