Gmail的三个片段动画场景的完整的工作样品? [英] Complete Working Sample of the Gmail Three-Fragment Animation Scenario?

查看:179
本文介绍了Gmail的三个片段动画场景的完整的工作样品?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR:我在寻找一个完整的工作是什么,我会称之为Gmail的三段动画场景示例。具体来说,我们要开始与两个片段,像这样的:

TL;DR: I am looking for a complete working sample of what I'll refer to as "the Gmail three-fragment animation" scenario. Specifically, we want to start with two fragments, like this:

当一些用户界面事件(例如,敲击东西在片段B),我们想要的:

Upon some UI event (e.g., tapping on something in Fragment B), we want:

  • 片段A滑动关闭屏幕向左
  • 片段B滑动到屏幕左侧边缘和收缩来接受片段A腾空现货
  • C片段从屏幕右侧的滑动,并采取了碎片B腾空现货

和,在BACK按钮preSS,我们希望这组操作被逆转。

And, on a BACK button press, we want that set of operations to be reversed.

现在,我已经看到了很多部分实现的;我将回顾他们四人以下。除了是不完整的,他们都有自己的问题。

Now, I have seen lots of partial implementations; I'll review four of them below. Beyond being incomplete, they all have their issues.

@Reto迈尔贡献这种流行的答案以相同的基本问题,这表明你会使用 setCustomAnimations() FragmentTransaction 。对于双片段的场景(例如,你只能看到片段A开始,并希望用一个新片段B使用动画效果代替),我完全同意。但是:

@Reto Meier contributed this popular answer to the same basic question, indicating that you would use setCustomAnimations() with a FragmentTransaction. For a two-fragment scenario (e.g., you only see Fragment A initially, and want to replace it with a new Fragment B using animated effects), I am in complete agreement. However:

  • 既然你只能指定一个中的一出的动画,我看不出你如何处理所有需要的三段场景中不同的动画
  • < objectAnimator> 在他的样本code使用像素硬连线的位置,而且似乎是不切实际给出不同的屏幕尺寸,但 setCustomAnimations()要求动漫资源,precluding定义在Java中这些事情的可能性
  • 在我不知所措的对象动画的规模如何配合像的android:layout_weight 的LinearLayout 有关百分比基础上分配空间
  • 我很茫然,如何C片段是在一开始就处​​理( GONE 机器人:layout_weight 0 ?$ P $的对动画来标度为0?别的东西吗?)
  • Since you can only specify one "in" and one "out" animation, I can't see how you would handle all the different animations required for the three-fragment scenario
  • The <objectAnimator> in his sample code uses hard-wired positions in pixels, and that would seem to be impractical given varying screen sizes, yet setCustomAnimations() requires animation resources, precluding the possibility of defining these things in Java
  • I am at a loss as to how the object animators for scale tie in with things like android:layout_weight in a LinearLayout for allocating space on a percentage basis
  • I am at a loss as to how Fragment C is handled at the outset (GONE? android:layout_weight of 0? pre-animated to a scale of 0? something else?)

@Roman Nurik指出能够绘制任何财产,包括那些你自己定义的。这可以帮助解决硬连线位置的问题,在发明自己的自定义布局管理器的子类的费用。这有助于一些,但我仍然对雷托的解决方案,剩下的困惑。

@Roman Nurik points out that you can animate any property, including ones that you define yourself. That can help solve the issue of the hard-wired positions, at the cost of inventing your own custom layout manager subclass. That helps some, but I'm still baffled by the rest of Reto's solution.

该引擎收录条目显示了一些诱人的伪code,基本上说,所有的三个片段将驻留在容器最初与C片段隐藏在一开始就通过隐藏()事务操作。然后,我们显示() C和隐藏() A当UI事件发生。但是,我不知道怎样处理的b变为大小的事实。这也依赖于事实,你显然可以添加多个片段相同的容器内,我不知道是否是长期可靠的行为(更何况这应该打破 findFragmentById() ,但我可以接受的)。

The author of this pastebin entry shows some tantalizing pseudocode, basically saying that all three fragments would reside in the container initially, with Fragment C hidden at the outset via a hide() transaction operation. We then show() C and hide() A when the UI event occurs. However, I don't see how that handles the fact that B changes size. It also relies on the fact that you apparently can add multiple fragments to the same container, and I am not sure whether or not that is reliable behavior over the long term (not to mention it should break findFragmentById(), though I can live with that).

的作者这个博客帖子表明Gmail未使用 setCustomAnimations()可言,而是直接使用对象的动画(你只是改变了右视图的根视图+变化宽度左边距)。然而,这仍然是一个两片段溶液AFAICT,和示出的实施再次硬导线尺寸中的像素

The author of this blog post indicates that Gmail is not using setCustomAnimations() at all, but instead directly uses object animators ("you just change left margin of the root view + change width of the right view"). However, this is still a two-fragment solution AFAICT, and the implementation shown once again hard-wires dimensions in pixels.

我会继续在这堵了,所以我可能最终有一天回答这个问题我自己,但我真的希望有人已经制定了这个动画场景三段解决方案,可以张贴code(或链接此)。在Android的动画让我想拉我的头发了,你们谁见过我知道,这基本上是一个徒劳的努力。

I will continue plugging away at this, so I may wind up answering this myself someday, but I am really hoping that somebody has worked out the three-fragment solution for this animation scenario and can post the code (or a link thereto). Animations in Android make me want to pull my hair out, and those of you who have seen me know that this is a largely fruitless endeavor.

在此先感谢!

推荐答案

好了,这是我自己的解决方案,从电子邮件AOSP应用程序得出,每@克里斯托弗的建议,在这个问题的意见。

OK, here is my own solution, derived from the Email AOSP app, per @Christopher's suggestion in the question's comments.

<一个href="https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePane">https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePane

@ weakwire的解决方案是让人想起我的,但他用经典的动画,而不是动画师,他用 RelativeLayout的规则执行的定位。从赏金的角度来看,他可能会获得赏金,除非别人用雨衣的解决方案尚未张贴的答案。

@weakwire's solution is reminiscent of mine, though he uses classic Animation rather than animators, and he uses RelativeLayout rules to enforce positioning. From the bounty standpoint, he will probably get the bounty, unless somebody else with a slicker solution yet posts an answer.

在一个概括地说, ThreePaneLayout 在该项目是一个的LinearLayout 的子类,设计景观的工作有三个儿童。这些儿童'的宽度可以在布局XML进行设置,通过任何期望的方式 - 我显示了使用权,但你可以有由维度的资源或任何设置特定的宽度。第三个孩子 - C片段中的问题 - 应该有一个零宽度

In a nutshell, the ThreePaneLayout in that project is a LinearLayout subclass, designed to work in landscape with three children. Those childrens' widths can be set in the layout XML, via whatever desired means -- I show using weights, but you could have specific widths set by dimension resources or whatever. The third child -- Fragment C in the question -- should have a width of zero.

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 的术语开关 - 这有没有具体联系的片段 - 这三个作品是离开。在你打电话的时间 hideLeft(),我们记录的大小离开和零出的是对上述三种中使用的任何权重,因此,我们可以完全控制的大小。在 hideLeft()的时间点,我们设置右键是原尺寸<$大小C $ C>中等。

However, at runtime, no matter how you originally set up the widths, width management is taken over by ThreePaneLayout the first time you use hideLeft() to switch from showing what the question referred to as Fragments A and B to Fragments B and C. In the terminology of ThreePaneLayout -- which has no specific ties to fragments -- the three pieces are left, middle, and right. At the time you call hideLeft(), we record the sizes of left and middle and zero out any weights that were used on any of the three, so we can completely control the sizes. At the point in time of hideLeft(), we set the size of right to be the original size of middle.

的动画是双重的:

  • 使用一个 ViewPropertyAnimator 执行三个小部件的翻译向左移的离开,使用宽硬件层
  • 使用的 ObjectAnimator middleWidth 修改自定义伪性中间从不管它开始为原宽度的宽度离开
  • Use a ViewPropertyAnimator to perform a translation of the three widgets to the left by the width of left, using a hardware layer
  • Use an ObjectAnimator on a custom pseudo-property of middleWidth to change the middle width from whatever it started with to the original width of left

(这是可能的,它是一个更好的主意,使用 AnimatorSet ObjectAnimators 所有这些,虽然这个工程现在)

(it is possible that it is a better idea to use an AnimatorSet and ObjectAnimators for all of these, though this works for now)

(它也可能是 middleWidth ObjectAnimator 否定了硬件层的价值,因为这需要相当连续无效)

(it is also possible that the middleWidth ObjectAnimator negates the value of the hardware layer, since that requires fairly continuous invalidation)

(它的绝对的可能,我仍然有我的动画COM prehension差距,而且我喜欢括号语句)

(it is definitely possible that I still have gaps in my animation comprehension, and that I like parenthetical statements)

净效应是,离开滑出屏幕,下滑的原始位置和大小离开右键翻译在后面

The net effect is that left slides off the screen, middle slides to the original position and size of left, and right translates in right behind middle.

showLeft()只是反转的过程中,与动画相同的组合,刚刚与方向逆转。

showLeft() simply reverses the process, with the same mix of animators, just with the directions reversed.

活动使用 ThreePaneLayout 持有一对 ListFragment 部件和一个按钮。选择一些在左片段增加(或更新的内容)的中间片段。中间段选择一些设置按钮的标题,再加上执行时 hideLeft() ThreePaneLayout 。 pressing回来,如果我们躲在左侧,将执行 showLeft();否则,返回退出的活性。由于这种不使用 FragmentTransactions 的影响的动画,我们卡管理的回栈自己。

The activity uses a ThreePaneLayout to hold a pair of ListFragment widgets and a Button. Selecting something in the left fragment adds (or updates the contents of) the middle fragment. Selecting something in the middle fragment sets the caption of the Button, plus executes hideLeft() on the ThreePaneLayout. Pressing BACK, if we hid the left side, will execute showLeft(); otherwise, BACK exits the activity. Since this does not use FragmentTransactions for affecting the animations, we are stuck managing that "back stack" ourselves.

该项目链接上面使用本机的碎片和本地动画框架。我还有一个版本,采用了Android支持片段的backport和 NineOldAndroids 为动画同一项目的:

The project linked-to above uses native fragments and the native animator framework. I have another version of the same project that uses the Android Support fragments backport and NineOldAndroids for the animation:

<一个href="https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC">https://github.com/commonsguy/cw-omnibus/tree/master/Animation/ThreePaneBC

的反向移植工作正常,在第一代Kindle Fire的,虽然动画是给定的较低的硬件规格和缺乏硬件加速的支持有点生涩。这两种实现方式似乎顺利上一台Nexus 7和其他当前一代的平板电脑。

The backport works fine on a 1st generation Kindle Fire, though the animation is a bit jerky given the lower hardware specs and lack of hardware acceleration support. Both implementations seem smooth on a Nexus 7 and other current-generation tablets.

我当然开放为如何改善这种解决思路,或者其他的解决方案,具有明显的优势在什么我在这里做(或者是什么@weakwire使用)。

I am certainly open for ideas of how to improve this solution, or other solutions that offer clear advantages over what I did here (or what @weakwire used).

再次感谢大家谁贡献!

这篇关于Gmail的三个片段动画场景的完整的工作样品?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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