Ant*_*427 5 java android android-animation android-scrollview
我有一个ScrollView
包含几个RelativeLayouts
,LinearLayouts
像这样:
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<RelativeLayout >
</RelativeLayout>
<LinearLayout >
</LinearLayout>
</ScrollView>
Run Code Online (Sandbox Code Playgroud)
现在,当我点击其中一个布局时,我希望它能够扩展并显示更多信息.我已经成功地通过以下方式缩放我想要的布局PropertyAnimator
:
relativeLayout.animate().scaleY(100).setDuration(duration).start();
Run Code Online (Sandbox Code Playgroud)
同时,我使用另一个PropertyAnimator
移动Views
到我垂直扩展的那个下方,以便有足够的空间用于扩展布局.到目前为止它正在运作.
不幸的是,Views
那个移动不知何故最终ScrollView
落在了视口之外,所以我无法向下滚动并查看其中的信息Views
.从本质上讲,这些视图的垂直平移使其下部无法访问,因为视口也不会扩展.
我已经开始android:fillViewPort="true"
了ScrollView
.而且我也试图以编程方式进行,setFillViewPort()
但都没有任何影响.
怎么了?为什么不起作用?
当你执行翻译动画时,Views
那些Views
并不真正在布局内移动.它只是为用户提供视觉效果,但在布局和/或测量时,忽略任何翻译值.它总是好像Views
根本没有翻译.
我猜你现在正在做的是:
View
您要扩展的内容.View
.Views
需要移动它们来执行翻译动画.Views
移出屏幕.这种方法实际上永远不会奏效.您始终需要记住Views
布局中的位置仅由布局确定.您的所有翻译基本上只是为了展示.所以当您尝试执行上述操作时,这就是实际发生的情况:
View
.Views
它们已经处于扩展后的位置,你的翻译动画只会向下移动Views
,超出它们应该的位置.Views
似乎没有明显的原因离开屏幕.那么你能做些什么呢?基本上你需要以相反的方式解决这个问题.正如我上面提到的,Android已经Views
为您计算了所有新的大小和位置,您可以利用它来获得优势.
您的问题有两种基本解决方案.您可以让Android为LayoutTransitions
您执行动画,也可以手动执行动画.两种方式都使用称为的东西ViewTreeObserver
.它可用于监听布局或新绘图过程中的更改.
但首要的是:ScrollView
应该只与一个孩子一起工作.因此,为了防止将来出现任何错误或问题,请将所有物品ScrollView
放在另一个LinearLayout
垂直方向的内部.
这仅适用于API Level 16及更高版本.在API级别16下方,可以自动处理可见性动画和平移动画,但要获得动画高度更改,您需要具有API级别16.
我必须提到的一件重要事情是:
LayoutTransition
动画为你改变.因此,如果您使用它,您可以删除所有自定义动画.如果您将自己的动画留在自己身上,则只会与执行的动画产生冲突LayoutTransition
.LayoutTransition
可以自定义它们!我将在下面解释如何进一步做到这一点.我通常使用这样的辅助方法来设置LayoutTransition
.
public static void animateLayoutChanges(ViewGroup container) {
final LayoutTransition transition = new LayoutTransition();
transition.setDuration(300);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
transition.enableTransitionType(LayoutTransition.CHANGING);
transition.enableTransitionType(LayoutTransition.APPEARING);
transition.enableTransitionType(LayoutTransition.CHANGE_APPEARING);
transition.enableTransitionType(LayoutTransition.DISAPPEARING);
transition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
}
container.setLayoutTransition(transition);
}
Run Code Online (Sandbox Code Playgroud)
这将启用API Level 16及更高版本上的所有可能的自动转换,并且只使用下面默认启用的转换.只需像这样使用它:
AnimatorUtils.animateLayoutChanges(linearLayout);
Run Code Online (Sandbox Code Playgroud)
如果你LinearLayout
在ScrollView
所有的高度/宽度/能见度的变化中调用此方法LinearLayout
,它的直接子项将为你动画.还会为您处理项目添加/删除动画.
要启用各种过渡,例如调整动画大小,您需要设置内置LayoutTransitions
代码,但是您可以通过设置属性来启用项目添加/删除动画等基本过渡
android:animateLayoutChanges="true"
Run Code Online (Sandbox Code Playgroud)
在ViewGroup
你的XML布局.
目前只有很少的文档LayoutTransitions
,但这里介绍了基础知识.
如果您愿意,可以为每个事件自定义动画,例如添加/删除View
或更改类似的内容View
:
// APPEARING handles items being added to the ViewGroup
transition.setAnimator(LayoutTransition.APPEARING, someAnimator);
// CHANGING handles among other things height or width changes of items in the ViewGroup
transition.setAnimator(LayoutTransition.CHANGING, someOtherAnimator);
Run Code Online (Sandbox Code Playgroud)
这是一个DevByte视频,它LayoutTransition
更详细地解释了s:
另请注意,当父级的高度发生变化时,容器视图可以基本上切断部分动画.这不会在你的情况发生,因为你ScrollView
有一个固定的大小和大小不会根据里面的孩子ScrollView
,但如果实施这样的事情在ViewGroup
有wrap_content
那么你需要设置android:clipChildren="false"
上述所有集装箱View
你想送动画.您也可以setClipChildren()
在代码中使用.
这比使用LayoutTransition
s 要困难得多,主要是因为你必须对布局和测量过程有很多了解,否则你会引起问题.然而,一旦掌握了它,你就可以执行各种自定义动画.
基本过程是这样的:
View
状态.View
s从旧位置动画到新位置此过程的核心是侦听视图层次结构中的更改.这是使用ViewTreeObserver
.您可以使用多种可能的回调,例如OnPreDrawListener
或OnGlobalLayoutListener
.通常你会像这样实现它们:
final Animator animator = setupAnimator();
animator.setTarget(view);
// Record the current state
animator.setupStartValues();
modifyChildrenOfLinearLayout();
linearLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// Remove the callback immediately we only need to catch it this one time.
linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Record the new state
animator.setupEndValues();
// Start the animation
animator.start();
}
});
Run Code Online (Sandbox Code Playgroud)
OnGlobalLayoutListener
因为在布局过程完成后调用布局更改,所以更好地捕获布局更改.OnPreDrawListener
在绘制下一帧之前调用,但它们不能保证布局过程已经完成.但在实践中,这种差异可以忽略不计.更重要的是,在较旧的较慢设备上,在新状态下布局可能会短暂闪烁,因为它们需要一些时间来处理每个步骤.你可以通过使用OnPreDrawListener
和返回false
一次来防止这种情况.由于OnGlobalLayoutListener
在大多数情况下您也应该在较新的API级别上完全可用OnPreDrawListener
.
如果LayoutTransitions
没有为您的问题提供适当的解决方案,并且您希望手动实现动画,那么学习如何有效地执行动画非常重要.你可以看一下LayoutTransition
这里的源代码.实现LayoutTransition
基本上完全是我在这里解释的,它是一个最佳实践实现.我经常发现自己正在查看android.animation
软件包的源代码,以了解有关如何高效动画的新内容,如果你想了解Android上的动画,我建议你也这样做!
您还可以观看一些有关此动画的Android DevBytes视频:
在这个视频中,他解释了如何ListView
使用一个动画来扩展一个扩展的单元格OnPreDrawListener
.
永远记住,Layouting Engine是你的朋友.不要试图重新发明轮子并手动完成布局过程已经为你做的事情.并且requestLayout()
在执行动画时不要打电话!
归档时间: |
|
查看次数: |
3007 次 |
最近记录: |