作为场景变换动画/过渡的一部分,如何设置高程变化的动画?

时间:2017-06-12 15:37:47

标签: android animation transition z-order elevation

在我的Android应用中,我需要实现一个场景转换,其中涉及其中一个元素的高程(z-index)的更改。正如您在左侧开始场景中的下图所示,蓝色弧线显示在狗的图像下方。在右侧显示的最终转换中,狗的图像显示在蓝色弧下方。我的愿望是首先启动图像的changeBounds转换,然后稍后稍稍执行arcBounds转换。在转换的大约一半时,图像的底部应位于弧的上方。在这个中间点,我想要改变图像的高程/ z指数,以便狗图像显示在蓝色弧下面。 before and after images

我目前已将我的应用主题配置为使用以下transitionSet进行此场景更改。

<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="together"
    android:duration="2000">

    <changeBounds
        android:startDelay="0"
        android:duration="1000"
        android:resizeClip="false"
        >
        <targets>
            <target android:targetId="@id/charlie"/>
        </targets>
    </changeBounds>

    <transition class="com.motb.transitiontest.ElevationTransition">
        android:startDelay="0"
        android:duration="1000"
        <targets>
            <target android:targetId="@id/charlie"/>
            <target android:targetId="@id/arc1"/>
        </targets>
    </transition>


    <changeBounds
        android:startDelay="300"
        android:duration="1000"
        >
        <targets>
            <target android:targetId="@id/arc1"/>
            <target android:targetId="@id/helloText" />
        </targets>
    </changeBounds>

</transitionSet>

我正在尝试使用下面显示的自定义“ElevationTransition”进行高程更改:

public class ElevationTransition extends Transition {

public static final String TAG = "ElevationTransition" ;

public ElevationTransition(Context context, AttributeSet attributes ) {
    super( context, attributes );
}

private static final String PROPNAME_TRANS_Z = "com.motb:transition:transz";
@Override
public void captureStartValues(TransitionValues transitionValues) {
    float translationZ = transitionValues.view.getTranslationZ() ;
    transitionValues.values.put(PROPNAME_TRANS_Z + "_start" , translationZ );
}

@Override
public void captureEndValues(TransitionValues transitionValues) {
    float translationZ = transitionValues.view.getTranslationZ() ;
    transitionValues.values.put(PROPNAME_TRANS_Z + "_end", translationZ );
}
@Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
                               TransitionValues endValues) {
    if (startValues == null || endValues == null) {
        return null;
    }
    final View view = endValues.view;
    float startElevation = (Float) startValues.values.get(PROPNAME_TRANS_Z + "_start");
    float endElevation = (Float) endValues.values.get(PROPNAME_TRANS_Z + "_end" );
    if (startElevation != endElevation) {
        view.setTranslationZ(startElevation);
        return ObjectAnimator.ofFloat(view, View.TRANSLATION_Z,
                startElevation, endElevation);
    }
    return null;
}

}

主要活动只使用以下布局显示空白地图:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.motb.transitiontest.MainActivity"
android:id="@+id/main"
android:onClick="onClick"
android:background="@drawable/treasuremap"
>

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="250dp"
    android:id="@+id/fragmentContainer"
    android:layout_alignParentBottom="true"
    />


</RelativeLayout>

点击地图会将上面的FrameLayout替换为显示使用以下布局的底部“卡片”的片段:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="250dp"
tools:context="com.motb.transitiontest.MainActivity"
android:id="@+id/main"
android:background="@android:color/transparent"
>


<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="160dp"
    android:background="@drawable/arc_bg"
    android:backgroundTint="#ff0000ff"
    android:layout_alignParentBottom="true"
    android:transitionName="rv1"
    android:id="@+id/arc1"
    android:translationZ="20dp"

    >

    <TextView
        android:id="@+id/helloText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World Transition Test"
        android:layout_marginStart="165dp"
        android:layout_marginTop="27dp"
        android:textSize="40dp"
        android:gravity="left"
        android:transitionName="tv1"
        android:textColor="#ffffffff"
        />


</RelativeLayout>

<ImageView
    android:layout_width="300px"
    android:layout_height="300px"
    android:layout_alignParentTop="true"
    android:layout_marginTop="80dp"
    android:layout_marginStart="20dp"
    android:transitionName="iv1"
    android:src="@drawable/charlie"
    android:id="@+id/charlie"
    android:translationZ="30dp"
    android:stateListAnimator="@null"
    />


</RelativeLayout>

单击片段,使用下面的xml以较大的狗图像开始第二个活动:

`
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.motb.transitiontest.Activity2"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
>


  <RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.motb.transitiontest.Activity2"
    android:layout_marginTop="200dp"
    android:background="@drawable/arc_bg"
    android:layout_alignParentBottom="true"
    android:transitionName="rv1"
    android:id="@+id/arc1"
    android:backgroundTint="#ff0000ff"
    android:translationZ="40dp"
    >


    <TextView
        android:id="@+id/helloText"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:layout_marginLeft="50dp"
        android:layout_marginRight="50dp"
        android:text="Hello World Transition Test"
        android:textSize="40dp"
        android:textAlignment="center"
        android:transitionName="tv1"
        android:textColor="#ffffffff"
        />


</RelativeLayout>


<ImageView
    android:id="@+id/charlie"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:src="@drawable/charlie"
    android:transitionName="iv1"
    android:scaleType="centerCrop"
    android:translationZ="0dp"
    android:stateListAnimator="@null"
    />



</RelativeLayout>`

目前,我看到的是,在过渡开始时海拔立即发生变化,导致狗图像被圆弧遮挡。

1 个答案:

答案 0 :(得分:2)

我检查了github。这是一个错误。

我可以使用Transtions和TransitionManager.go()分别运行场景之间的转换。但是,当您在片段和活动之间运行转换时,始终会立即更改淡入淡出动画。在Support 26.0.0 beta-1

中修复了几个淡入淡出错误
  • 当淡入淡出过渡被中断并反转时,视图从头开始动画。 (从Android Framework移植的修复程序。)
  • Transition.Fade忽略View的初始alpha(AOSP issue 221820)

但是,问问自己,你所有的小提琴你曾经看到它做了一个真正的淡入淡出过渡? - 没有。比如忽略所有的动作和其他什么,你能让它完全褪色吗?因为我的所有建议都需要,而且我无法按照你运行的方式运行它。但是,显然所有元素的移动都有效,所以它是一个该死的bug。

你也可以完全伪造它。如果你已经淡出,你可以调用它并让它工作。如果将Activity2中的onCreate()更改为:

,则会获得正确的动画
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);

    setContentView(R.layout.activity2);
    findViewById(R.id.arc1).setVisibility(View.VISIBLE);
    findViewById(R.id.arc2).setAlpha(0);
    findViewById(R.id.arc2).animate().alpha(1).setDuration(2000).start();
}

我只将arc1的可见性设置为正确的,因为你错了。这是一个始终可见的那个。

我认为然后在相同的时间段内添加一个动画,与另一个相同,以进行相位调整。有用。这是一个愚蠢的错误。根本没有充分理由,你不能在活动之间消失。

我自己发现了阿尔法。第一个可能是发生了什么。或者它可能是完全不同的一类错误。但是,我可以向你保证。我检查并做好了一切。它仍然失败了。显然,解决方法是使用他们工作的场景转换。也许根本不使用新的活动。

您可以明显地提出一些解决方法。只需使用它应该具有的布局启动活动,然后设置场景以转换到正确的布局。在第一个活动中自己添加另一个到布局的过渡。或者诸如此类的。但是,它不起作用。你做了从片段到活动的过渡,然后东西会移动,但是淡入淡出总会引发一种情绪并拒绝。它立即具有其他视图的可见性,并且没有alpha工作,也没有办法轻易纠正。

我的原始代码有一些工作是使用场景:

boolean to = true;
public void onClick(View view) {
    Scene scene;
    ViewGroup mSceneRoot = (ViewGroup) findViewById(R.id.container);
    if (to) {
        Transition mFadeTransition =
                TransitionInflater.from(this).
                        inflateTransition(R.transition.transitionset);
        scene = Scene.getSceneForLayout(mSceneRoot, R.layout.fragment_replacement, this);

        TransitionManager.go(scene, mFadeTransition);
    }
    else {
        Transition mFadeTransition =
                TransitionInflater.from(this).
                        inflateTransition(R.transition.backwardstransitionset);
        scene = Scene.getSceneForLayout(mSceneRoot, R.layout.fragment_rep, this);
        TransitionManager.go(scene, mFadeTransition);
    }
    to = !to;
}

当我认为无法实现我对如何进行转换的非常明确的想法时,留下一些旧答案。这个错误是他没有那个有效的褪色,而这一直是问题所在。

您无法仅使用Z顺序制作动画。你改变了顺序,他们在彼此之上绘制而不是相反。做你想要做的事情就是有效地同时两个订单,并以透明度动画他们的过渡。

你画,弧,狗,另一个弧。然后,Z顺序的变化实际上是顶部绘制的圆弧的透明度。如果它完全不透明,那么弧就在狗的顶部。如果它完全透明,那么狗就在弧上。但是,如果最顶部的弧是部分透明的,它看起来像狗正在通过弧线融化,或者弧线正在融化狗,这取决于我们如何调整透明度。你可以在其他地方采用相同的技巧。把东西放在两个地方。如果它是不透明的,它会被覆盖,但如果它是透明的,它只显示最下面的弧,如果是部分透明的话,弧与物体之间的混合。在动画结束时,只需按正确顺序排列。

因此,在动画期间,您始终将2个弧移动到相同的位置。您应该将它们视为相同的弧形。并在顶部改变弧的不透明度,并做任何你对那条狗做的事情。

视频:

https://youtu.be/zVs3qzPU2FM

创建布局。将您希望在另一个对象的两个副本之间更改高度的位三明治。在其中一个布局中,将可见性设置为invisible。因此,所有项目都以相同的顺序在两个布局中。但是,在一个中,所讨论的元素的第二个副本是不可见的。确保两个副本在两个副本中处于相同位置。更改一个副本的边界时,请确保也更改另一个副本的边界。将它们作为一个整体移动。转换视图时,将项目淡出,同时移动它或诸如此类的东西。由于第二个副本不会看起来像淡出,它看起来像是一个融化。