3面板布局片段动画口吃 [英] 3 pane layout fragment animation is stuttering

查看:148
本文介绍了3面板布局片段动画口吃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

的实施方式: 我已经实施了3面板布局下贴在了自己的问题在这里CommonsWare响应:<一href="http://stackoverflow.com/questions/12253965/complete-working-sample-of-the-gmail-three-fragment-animation-scenario">Complete Gmail的三个片段动画场景的工作示例?

作为一般的想法,我有布局由以下级别(1〜3):

  1. MainActivity
  2. SlidingMenu (侧抽屉UI模式)片段隐藏在左侧和 ContentFragment 的片段房屋3面板布局。
  3. ContentFragment LeftListFragment (3 TextViews行,每行), MiddleListFragment DetailFragment
  4. (每条8 TextViews行)

LeftListFragment MiddleListFragment 使用 CursorLoaders 来加载数据从的ContentProvider 每个列表中。 DetailFragment 还需要的时候要求一个光标数据。所以,我甚至没有实现自定义的适配器(好得多设计这种方式)。于是我加了3面板布局+动画。至于工作,它的作品如预期,有没有问题。 动画时间为500ms。

的问题: 该动画口吃一点。一些丢帧。无论在左,中是可见的,我点击中间的列表项打开一个细节;而且,当我点击返回按钮再次见到左,中列表(没事的时候其实是加载)。

我已经试过:

  1. 移除了code加载在的DetailView 片段。我只是挖掘 MiddleFragment 的项目和动画开始,没有任何详细的实际加载。还有口吃。此外,打回来的时候,什么都没有加载,它仍然结结巴巴,所以我presume装载机/游标是不是这个原因。
  2. 在我以前dumpsys gfxinfo看到的平均时间以毫秒来计算每一帧。实际上,平均时间为一个计算是18毫秒,这是高于16ms的阈值。那么,这是否意味着口吃是因为它需要重新绘制,在动画列表的时间?如果是这样,为什么呢?我的意思是......我没有在里面所有的行意见的任何图像。我不能搞砸了适配器code,因为我没有写任何...
  3. 降低动画的时间从500毫秒到200毫秒。它仍然结结巴巴,如果你真的仔细看它,它只是速度更快。

编辑:我从 rightPaneWidth 切换到 leftPaneWidth 下方(是的,去除重新标注的动画)和口吃,现在没有了。列表仍然滑动到左侧,但它只是没有得到在宽度。所以,如果没有更多的现在口吃,这是否意味着有一个在我的code中的ObjectAnimator有问题吗?

  ObjectAnimator.ofInt(这一点,middleWidth,rightPaneWidth,leftPaneWidth)
                    .setDuration(ANIM_DURATION)。开始();
 

感谢您的时间!

code 3面板布局:

 包com.xyz.view.widget;

进口android.animation.ObjectAnimator;
进口android.annotation.Sup pressLint;
进口android.annotation.TargetApi;
进口android.content.Context;
进口android.util.AttributeSet;
进口android.view.View;
进口android.view.ViewPropertyAnimator;
进口android.widget.LinearLayout;


公共类ThreePaneLayout扩展的LinearLayout
{
    私人查看leftView = NULL;
    私人查看middleView = NULL;
    私人查看rightView = NULL;

私有静态最终诠释ANIM_DURATION = 500;
私人诠释leftPaneWidth = -1;
私人诠释rightPaneWidth = -1;


// ------------------------------------------------ -------------------------------------------
// --------------构造
// ------------------------------------------------ -------------------------------------------


公共ThreePaneLayout(上下文的背景下,ATTRS的AttributeSet)
{
    超(背景下,ATTRS);
    setOrientation(水平);
}

@覆盖
公共无效onFinishInflate()
{
    super.onFinishInflate();
    leftView = getChildAt(0);
    middleView = getChildAt(1);
    rightView = getChildAt(2);
}


// ------------------------------------------------ -------------------------------------------
// --------------公共方法
// ------------------------------------------------ -------------------------------------------


公共查看getLeftView()
{
    返回leftView;
}

公共查看getMiddleView()
{
    返回middleView;
}

公共查看getRightView()
{
    返回rightView;
}

@燮pressLint(NewApi)
公共无效hideLeft()
{
    如果(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(这一点,middleWidth,rightPaneWidth,leftPaneWidth)
                    .setDuration(ANIM_DURATION)。开始();
}

@燮pressLint(NewApi)
公共无效showLeft()
{
    translateWidgets(leftPaneWidth,leftView,middleView,rightView);
    ObjectAnimator.ofInt(这一点,middleWidth,leftPaneWidth,rightPaneWidth)
                    .setDuration(ANIM_DURATION)
                    。开始();
}


// ------------------------------------------------ -------------------------------------------
// --------------私有方法
// ------------------------------------------------ -------------------------------------------


私人无效setMiddleWidth(int值)
{
    。middleView.getLayoutParams()宽度=价值;
    requestLayout();
}

@TargetApi(12)
私人无效translateWidgets(INT DELTAX,查看...查看)
{
    对于(最后查看的观点:观点)
    {
        ViewPropertyAnimator viewPropertyAnimator = view.animate();
        viewPropertyAnimator.translationXBy(DELTAX)
                            .setDuration(ANIM_DURATION);
    }
  }

  私人无效resetWidget(查看视图,诠释宽度)
  {
      LinearLayout.LayoutParams的LayoutParams =(LinearLayout.LayoutParams)view.getLayoutParams();
      layoutParams.width =宽度;
      layoutParams.weight = 0;
  }
}
 

XML的ContentFragment:

 &LT; XML版本=1.0编码=UTF-8&GT?;
&LT; com.xyz.view.widget.ThreePaneLayout的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    机器人:ID =@ + ID / fragment_content_three_pane_layout
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent&GT;

&LT;的FrameLayout
    机器人:ID =@ + ID / fragment_content_framelayout_left
    机器人:layout_width =0dp
    机器人:layout_height =match_parent
    机器人:layout_weight =3/&GT;

&LT;的FrameLayout
    机器人:ID =@ + ID / fragment_content_framelayout_middle
    机器人:layout_width =0dp
    机器人:layout_height =match_parent
    机器人:layout_weight =7/&GT;

&LT;的FrameLayout
    机器人:ID =@ + ID / fragment_content_framelayout_right
    机器人:layout_width =0dp
    机器人:layout_height =match_parent/&GT;
&LT; /com.xyz.view.widget.ThreePaneLayout>
 

解决方案

问题不在于ObjectAnimator,而是你的应用程序简单地做太多动画的每一帧。具体而言,你是动画布局PARAMS和布局要求对每一帧。布局是强大的和有用的......但可以在任何相当昂贵的,但最琐碎的视图层次。重要的是要避免在动画每帧昂贵的操作和布局属于这种贵的范畴。左右滑动的东西是好的(translationX / Y),褪色的东西输入/输出还是不错的(阿尔法),但实际上铺设的事情了每一帧?只是说没有。

The implementation info: I have implemented a 3 pane layout following CommonsWare response posted on his own question over here: Complete Working Sample of the Gmail Three-Fragment Animation Scenario?

As a general idea, I have the layout comprised of following levels (1 through 3):

  1. MainActivity
  2. SlidingMenu (Side Drawer UI pattern) fragment hiding on the left side and a ContentFragment as the fragment that houses the 3 Pane Layout.
  3. Inside the ContentFragment: LeftListFragment (rows with 3 TextViews each), MiddleListFragment (rows with 8 TextViews each), DetailFragment.

LeftListFragment and MiddleListFragment use CursorLoaders to load data from a ContentProvider inside each list. DetailFragment also calls for a cursor with data when needed. So I didn't even implement custom Adapters (much nicer design this way). Then I have added the 3 Pane layout + animations. As far as working, it works as intended, no problems there. Animation time is 500ms.

The problem: The animations stutter a little. A few dropped frames. Both when the Left and Middle are visible and I click on a Middle list item to open a Detail; and also when I tap the Back button to see again Left and Middle lists (when nothing is actually loading).

What I've tried:

  1. Removed the code that loads the fragment in DetailView. I just tap an item in MiddleFragment and the animation begins, without any Detail actually loading. Still stutters. Also, when hitting back, nothing loads and it still stutters, so I presume the loaders/cursors are not the cause of this.
  2. I used dumpsys gfxinfo to see the average time in ms to compute each frame. Indeed, the avg time for a computation is 18ms, which is above the 16ms threshold. So does this mean the stuttering is because of the time it takes to draw again the lists, when animating ? If so, why ? I mean... I don't have any images at all inside row views. And I couldn't screw up the Adapters code, because I haven't written any...
  3. Reducing the Animation time from 500ms to 200ms. It still stutters if you watch it really carefully, it's just faster.

EDIT: I switched from rightPaneWidth to leftPaneWidth below (yes, that removes the re-dimensioning animation) and the stuttering is now gone. The list still slides to the left side, but it just doesn't get smaller in width. So if there is no more stuttering now, does that mean there is a problem with the ObjectAnimator in my code ?

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

Thanks for your time !

Code for 3 Pane Layout:

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;
  }
}

XML for the ContentFragment:

    <?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>

解决方案

The problem is not ObjectAnimator, but rather that your application is simply doing too much on every frame of the animation. Specifically, you are animating layout params and requesting layout on every frame. Layout is powerful and useful... but can be quite expensive in any but the most trivial of view hierarchies. It's important to avoid expensive operations per-frame during animations, and layout falls into that "expensive" category. Sliding things around is fine (translationX/Y), fading things in/out is good (alpha), but actually laying things out on every frame? Just say no.

这篇关于3面板布局片段动画口吃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆