Gmail的三个片段动画场景的完整的工作样品? [英] Complete Working Sample of the Gmail Three-Fragment Animation Scenario?
问题描述
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, yetsetCustomAnimations()
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 aLinearLayout
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
of0
? 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 ofleft
, using a hardware layer - Use an
ObjectAnimator
on a custom pseudo-property ofmiddleWidth
to change themiddle
width from whatever it started with to the original width ofleft
(这是可能的,它是一个更好的主意,使用 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屋!