gpt4 book ai didi

java - 动画 View 移出我的布局

转载 作者:行者123 更新时间:2023-12-04 18:39:45 27 4
gpt4 key购买 nike

我有一个 ScrollView其中包含多个 RelativeLayoutsLinearLayouts像这样:

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

现在,当我单击这些布局之一时,我希望它展开并显示更多信息。我设法通过使用 PropertyAnimator 垂直缩放我想要的布局来做到这一点。 :
relativeLayout.animate().scaleY(100).setDuration(duration).start();

同时,我使用另一个 PropertyAnimator移动任何 Views在我垂直展开的下方,以便为展开的布局留出足够的空间。到目前为止它正在工作。

不幸的是, Views该移动以某种方式最终超出了 ScrollView 的视口(viewport)之外,所以我无法向下滚动并查看 Views 中的信息.本质上,这些 View 的垂直平移使其下部无法到达,因为视口(viewport)也不会扩展。

我已经设置了 android:fillViewPort="true"ScrollView .而且我还尝试使用 setFillViewPort() 以编程方式进行操作但两者都没有任何影响。

怎么了?为什么它不起作用?

最佳答案

当您在 Views 上执行翻译动画时那么那些Views不要真正在布局内移动。它对用户来说只是视觉效果,但在布局和/或测量时,任何翻译值都将被忽略。它总是好像 Views根本没有翻译。

我猜你现在正在做的是:

  • 您对点击事件使用react并展开 View你想扩展。
  • 您计算其他 View 需要移动多少才能容纳扩展 View .
  • 然后你对那些 Views 执行翻译动画他们需要移动很多。
  • 然后结果突然几个Views移出屏幕。

  • 这种方法实际上永远行不通。你总是需要记住一个 Views布局中的位置确定 只是 由布局。你所有的翻译基本上只是为了展示。因此,当您尝试执行上述操作时,实际情况如下:
  • 您对点击事件使用react并展开 View .
  • 这种扩展会导致 Android 开始布局和测量过程。计算所有 View 的位置和大小,并将它们以新的大小放置在新位置。
  • 从现在起Views已经在他们将要到达的位置之后,您的翻译动画只是移动了 Views进一步下降,超出了他们应该达到的程度。
  • 作为此的副作用 Views似乎无缘无故地移出屏幕。

  • 那么你能做些什么呢?本质上,您需要以相反的方式解决这个问题。正如我上面提到的,Android 已经计算了所有 Views 的新尺寸和位置。对你来说,你可以利用它来发挥你的优势。

    您的问题有两种基本解决方案。您可以使用 LayoutTransitions 让 Android 为您执行动画或者您手动执行动画。两种方式都使用一种叫做 ViewTreeObserver 的东西。 .它可用于监听布局或新绘图过程中的更改。

    但最重要的是: ScrollView应该只和一个 child 一起工作。因此,为了防止将来出现任何错误或问题,请将您的所有项目放入 ScrollView另一个内部 LinearLayout与垂直方向。

    1) 使用 LayoutTransition

    这仅适用于 API 级别 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);
    }

    这将启用 API 级别 16 及更高级别上所有可能的自动转换,并仅使用低于该级别的默认启用转换。只需像这样使用它:
    AnimatorUtils.animateLayoutChanges(linearLayout);

    如果你在 LinearLayout 上调用这个方法在您的 ScrollView然后对 LinearLayout 的高度/宽度/可见性的所有更改它的直系子代会为你动画。项目添加/删除动画也会为您处理。

    要启用各种过渡,如调整大小动画,您需要设置 LayoutTransitions在代码中,但您可以通过设置属性来启用基本转换,如项目添加/删除动画
    android:animateLayoutChanges="true"

    ViewGroup在您的 xml 布局中。

    LayoutTransitions 上只有最少的文档。 ,但涵盖了基础知识 here .

    如果您愿意,您可以为每个事件自定义动画,例如添加/删除 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);

    这是一个 DevByte 视频,它解释了 LayoutTransition更详细的:
  • LayoutTransitions enable easy fade/move/resize animations

  • 另请注意,当父 View 的高度发生变化时,容器 View 本质上可以切断部分动画。这不会发生在你的情况下,因为你的 ScrollView具有固定大小,不会根据 ScrollView 中的子项调整大小,但如果你在 ViewGroup 中实现类似的东西与 wrap_content那么你需要设置 android:clipChildren="false"View 上方的所有容器上s 您正在尝试制作动画。您也可以使用 setClipChildren()在代码中。

    2)手动动画所有项目。

    这比使用 LayoutTransition 困难得多。 s,主要是因为你要知道很多布局和测量过程,否则你会出问题。然而,一旦掌握了它,您就可以执行各种自定义动画。

    基本流程是这样的:
  • 记录电流 View状态。
  • 将布局更改为动画完成后的状态
  • 在 Android 完成布局和测量后,记录新值。
  • 现在动画 View s 从旧位置到新位置

  • 这个过程的核心是监听 View 层次结构的变化。这是使用 ViewTreeObserver 完成的.您可以使用多种可能的回调,例如 OnPreDrawListenerOnGlobalLayoutListener .通常你会像这样实现它们:
    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();
    }
    });
    OnGlobalLayoutListener更擅长捕捉布局变化,因为它在布局过程完成后被调用。 OnPreDrawListener在绘制下一帧之前调用,但不能保证布局过程已经完成。但在实践中,这种差异可以忽略不计。更重要的是,在较旧的较慢设备上,布局可能会在新状态下短暂闪烁,因为它们需要一些时间来处理每个步骤。您可以通过使用 OnPreDrawListener 来防止这种情况发生。并返回 false一次。自 OnGlobalLayoutListener也仅在较新的 API 级别上完全可用,您应该在大多数情况下使用 OnPreDrawListener .

    LayoutTransitions没有为您的问题提供足够的解决方案,并且您必须/想要手动实现动画,而不是学习如何有效地执行动画很重要。可以看 LayoutTransition的源码 here . LayoutTransition的实现基本上完全符合我在这里解释的内容,它是最佳实践实现。我经常发现自己在查看 android.animation 的源代码包以学习有关如何有效制作动画的新知识,如果您想了解 Android 上的动画,我建议您也这样做!

    您还可以观看一些关于动画的 Android DevBytes 视频,如下所示:
  • ListView Expanding Cells Animation

  • 在此视频中,他解释了如何在 ListView 中为扩展单元设置动画。通过使用 OnPreDrawListener .

    永远记住,布局引擎是你的 friend 。不要试图重新发明轮子并手动完成布局过程已经为您完成的工作。永远不要打电话 requestLayout()在执行动画时!

    关于java - 动画 View 移出我的布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29168964/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com