1)关于赏金:
SO上的现有答案建议将FrameLayout子类化......
如果你想使用 anObjectAnimator
你别无选择,只能将View
你想要动画的子类化。您需要提供ObjectAnimator
必要的 getter 和 setter 方法来发挥它的魔力,因为它本质上只是调用这些 getter 和 setter 方法来执行Animation
.
您链接到的问题(动画片段之间的过渡)是子类化FrameLayout
以添加 asetXFraction()
和 agetXFraction()
方法。它们的实现方式是将 x 值设置为相对于FrameLayout
. 只有这样做才能ObjectAnimator
在绝对值之间进行动画处理之外的其他任何事情。
总而言之,它ObjectAnimator
本身实际上并没有做太多动画,它只是通过反射调用 getter 和 setter 方法。
真的没有办法将实际的屏幕像素尺寸(不仅仅是 dp)放入 xml 文件吗?
没有ObjectAnimator
办法做到这一点。ObjectAnimators
只需从起始值到结束值进行插值。正如我上面解释的,setter 方法定义了实际发生的情况。
例如,调用一个返回宽度的自定义函数就可以了,或者定义一个代码可以设置的常量,让代码将所述常量设置为等于屏幕宽度,然后从 xml 访问该常量同样有用。
您不能将代码中的任何值插入到任何 xml 资源中。xml 文件中包含的所有内容都会在您构建时编译到您的 APK 中,并且在运行时无法更改。这也是对您其他问题的回答:在包含当前屏幕大小的 xml 中没有可访问的资源或常量或任何内容。安装应用程序的设备的屏幕大小等动态值不能成为这些资源的一部分,因为它们中的所有内容都在您构建应用程序时编译到您的应用程序中。
2)可能的解决方案:查看动画
一种可能的解决方案是使用视图动画而不是ObjectAnimator
. 使用视图动画,您可以指定分数而不仅仅是绝对值:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="-100%" android:toYDelta="0%" android:duration="1000"/>
</set>
这将为屏幕高度的View
从-100%
到设置动画。0%
换句话说,从完全的屏幕到 的位置View
。你可以像这样使用它:
Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down);
view.startAnimation(animation);
我意识到这可能对你没有任何帮助。在某些情况下,必须使用ObjectAnimators
且不能使用视图动画。但是只要您能够使用视图动画,这应该可以解决您的问题。
3) 最佳实践
我们真正应该在这里解决的是我认为您的误解。正如您已经注意到,您在 xml 中定义的每个动画都有绝对的开始和结束值。这些值是静态的,在编译您的应用程序后无法更改。
如果您查看资源如何与许多可用的选择器以及 dp、sp... 一起工作,那么您将意识到它旨在做一件事:
例如,您可以定义一个将 a 移动View
100dp 的动画。Dp 是物理尺寸的度量,100dp 与任何像素密度的任何屏幕的物理尺寸完全相同。通过选择器,您可以为具有更小或更大屏幕的设备更改此动画,其中动画可能移动View
太多或太少。但是你只能填写静态值。除了使用选择器之外,您无法为每个设备自定义动画。
所以你看,资源真的只是为任何静态和不变的东西而设计的。它适用于尺寸或字符串转换,但有时使用动画可能会有点痛苦。正如我上面所说,只有视图动画通过提供指定分数而不是绝对值的选项来提供一种绕过静态性质的方法。但一般来说,你不能在 xml 中定义任何动态的东西。
为了进一步证实这一论点,请查看谷歌关于动画的优秀 DevBytes 视频:
然后您会注意到,这些示例中没有一个动画是在 xml 中定义的。当然有人可能会争辩说他们没有在 xml 中定义它们,因为他们希望更轻松地解释和显示代码,但在我看来,这再次证明了一点:
您不能在依赖于纯动态值的静态资源中定义动画
由于屏幕宽度/高度因设备而异,因此您需要为每个设备设置不同的动画。只有视图动画提供了一种解决方法,因为它们允许您定义分数而不是绝对值。在任何其他情况下,您都需要以编程方式定义动画。幸运的是,这并不难ObjectAnimators
:
Animator animator = ObjectAnimator.ofFloat(view, View.X, startValue, endValue);
animator.start();
这将以View
像素为单位对从开始到结束值的 x 位置进行动画处理。您可以传递 的宽度View
以像您想要的那样对其进行动画处理:
Animator animator = ObjectAnimator.ofFloat(view, View.X, -view.getWidth(), 0.0f);
animator.start();
这将使View
从左侧滑入的动画。它完全在屏幕外开始并在其最终位置停止。你也可以这样做:
view.animate().x(targetValue);
这会将其View
从当前 x 位置动画到目标 x 值。
但请不要误会我,您仍然应该尝试在资源中尽可能多地定义 - 无论是动画还是其他任何东西。应尽可能避免硬编码动画或任何其他值,除非在您的情况下有必要。
4) 总结
所以总结一下:
ObjectAnimators
如果不将所需的 getter 和 setter 方法添加到View
要制作动画的对象中,您将无法做您想做的事情。
- 如果可能的话,使用视图动画。使用它们,您可以根据
View
.
- 如果上述方法不起作用或不适用于您的情况,则以编程方式定义动画,这在任何情况下都有效。
我希望我能帮助你,如果你有任何进一步的问题,请随时提问!