将 SharedElement Activity 转换与自定义视图一起使用

Posted

技术标签:

【中文标题】将 SharedElement Activity 转换与自定义视图一起使用【英文标题】:Using SharedElement Activity transitions with a custom View 【发布时间】:2017-05-26 22:15:13 【问题描述】:

我正在做一个概念验证,我在 TableLayout 中有一些自定义视图。单击其中一个视图时,我想将视图动画化为一个新的活动。我想要达到的效果和here看到的差不多。

根据我的研究,似乎可以使用shared element Transitions。但是,我无法让它正常工作,我想知道是不是因为我使用的是我自己的自定义视图。

具体来说,淡入淡出正在发生,但缩放和平移运动并未发生。检查下面的 GIF,看看我在哪里。在示例中,我单击左上角的圆圈,我想将其转换为新活动中的完整圆圈。按下后退按钮时也会出现此问题。

我认为这是不正确的,因为必须绘制视图,但是有没有办法进一步自定义我的视图以使其工作?我发现的所有此类转换的示例都包含 ImageViews、Buttons 和 TextViews。

以下是相关来源。我的自定义视图很大,不包含任何特殊代码,只是覆盖了 onDraw() 和 onMeasure()。

MainActivity.java

package com.rscottcarson.circleschedulertest;

import android.app.Activity;
import android.app.ActivityOptions;
import android.content.Intent;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Toast;
public class MainActivity extends Activity 

    private View view1;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        view1 = findViewById(R.id.circle1);

        view1.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 

                Intent intent = new Intent(MainActivity.this, DetailActivity.class);
                // create the transition animation - the images in the layouts
                // of both activities are defined with android:transitionName="profile"
                ActivityOptions options = ActivityOptions
                        .makeSceneTransitionAnimation(MainActivity.this, view1, "profile");
                // start the new activity
                startActivity(intent, options.toBundle());
            
        );

    

DetailActivity.java

package com.rscottcarson.circleschedulertest;

import android.app.Activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class DetailActivity extends Activity 

    @Override
    protected void onCreate(Bundle savedInstanceState)
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

    

change_image_trans.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
    <changeTransform />
</transitionSet>

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
        <item name="android:windowActivityTransitions">true</item>
        <item name="android:windowContentTransitions">true</item>

        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>


        <!-- specify shared element transitions -->
        <item name="android:windowSharedElementEnterTransition">
            @transition/change_image_trans</item>
        <!-- specify shared element transitions -->
        <item name="android:windowSharedElementExitTransition">
            @transition/change_image_trans</item>
    </style>

</resources>

【问题讨论】:

【参考方案1】:

在您的DetailActivity 中尝试使用postponeEnterTransition()startPostponedEnterTransition()

postponeEnterTransition() 用于暂时延迟转换,直到共享元素被正确测量和布局。

startPostponedEnterTransition() 安排共享元素转换在共享元素被测量并在活动的视图层次结构中布局后立即启动。

DetailActivity.java

@Override
protected void onCreate(Bundle savedInstanceState)
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_detail);
    postponeEnterTransition();


private void scheduleStartPostponedTransition(final View sharedElement) 
    sharedElement.getViewTreeObserver().addOnPreDrawListener(
        new ViewTreeObserver.OnPreDrawListener() 
            @Override
            public boolean onPreDraw() 
                sharedElement.getViewTreeObserver().removeOnPreDrawListener(this);
                startPostponedEnterTransition();
                return true;
            
        );

【讨论】:

【参考方案2】:

我不认为您的问题在于您有自定义视图...我总是使用自定义视图进行这些转换并且它们工作正常。

我可以看到这段代码:

ActivityOptions options = ActivityOptions
                        .makeSceneTransitionAnimation(MainActivity.this, view1, "profile");
                // start the new activity 
                startActivity(intent, options.toBundle());

没有做你想做的事。

这是你需要做的:

首先,使用过渡创建您的 xml:

第一个活动

<YouCustomView
     android:id="@+id/someId"
     android:layout_
     android:layout_
     android:transitionName="@string/someTransition">

第二个活动:

<YouCustomView
         android:id="@+id/someOtherId"
         android:layout_
         android:layout_
         android:transitionName="@string/someTransition">

第二个,当你开始第二个活动时,这样做:

        ActivityOptions activityOptions = ActivityOptions.makeSceneTransitionAnimation(
    this, new Pair<>(findViewById(R.id.someId), getString(R.string.someTransition))

startActivity(intent, activityOptions.toBundle());

您忘记添加带有视图和过渡名称的 Pair。添加它,您的过渡将正常工作。您的视图是自定义视图这一事实不会改变动画。

编码愉快!

【讨论】:

以上是关于将 SharedElement Activity 转换与自定义视图一起使用的主要内容,如果未能解决你的问题,请参考以下文章

将多个 Intent 从单个 Activity 发送到另一个 Activity

将上下文从 Activity 传递到静态类是不是会永久保留该 Activity?内存泄漏?

如何将 Twitter Fabric 会话从 Activity 发送到另一个 Activity?

如何将数据从一个 Activity 中的 ListView 传递到另一个 Activity 上的 TextView?

将 SQLite 表数据显示到列表视图中,就在将数据插入同一 Activity 上的表之后,无需关闭 Activity 并重新打开

将蓝牙连接传递给新的 Activity