【发布时间】:2017-06-20 09:49:49
【问题描述】:
在我的 Android 应用中,我需要实现一个场景转换,该转换涉及改变其中一个元素的高度(z-index)。正如您在下图中左侧开始场景中看到的那样,蓝色弧线显示在狗的图像下方。在右侧显示的最终过渡中,狗的图像显示在蓝色弧线下方。我的愿望是首先开始图像的 changeBounds 过渡,然后稍晚进行圆弧的 changeBounds 过渡。在过渡的大约一半处,图像的底部应位于圆弧上方。在这个中间点,我希望图像的高程/z-index 发生变化,以便狗图像显示在蓝色弧线下方。
我目前已将我的应用主题配置为使用以下 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>`
目前,我看到的是,在过渡开始时海拔会立即发生变化,导致狗的图像被弧线遮挡。
【问题讨论】:
-
一个更优雅和有效的解决方案是编写你的自定义类来绘制具有渐进 z 索引的图像,你可以使用 valueAnimator 为你的动画提供平滑度
-
@sumit 请提供更多详细信息,说明为什么您认为在这种情况下 valueAnimator 比 ObjectAnimator 更好。是什么让它更优雅、更高效?
-
您也可以发布视图层次结构吗?
-
@azizbekian - 我将 xml 布局添加到问题的底部。
标签: android animation transition z-order elevation