共享元素过渡不起作用 [英] Shared Element Transition not working

查看:70
本文介绍了共享元素过渡不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经完成了一个github项目.您可以在此处查看/克隆/构建它: https://git.io/vMPqb

I have made a github project with just the issue. You can see it / clone it / build it from here: https://git.io/vMPqb

我正在尝试让共享元素可以用于Fragment过渡.

I am trying to get shared elements working for a Fragment transition.

该项目中有两个FAB-羽毛和飞机.羽毛和飞机是共享元素.单击羽化"时,将打开SheetDialog,并且羽化应该在平面"对话框上进行动画处理.目前,它还没有这样做,我正在尝试确定原因.

There are two FABs in the project - Feather and Plane. Feather and Plane are shared elements. When Feather is clicked, the SheetDialog is opened, and Feather should animate over to Plane dialog. It does not do that at the moment, and I am trying to determine why.

也许值得一提的是,我正在API 24上运行此代码,所以在21版以下不支持转换的问题就不是问题了.

It may be worthwhile noting that I am running this on API 24 so issues with transitions not being supported below version 21 is not the problem.

谁能告诉我为什么共享元素过渡不起作用?

Can anyone tell me why shared element transitions are not working?

要回显仓库中的内容,有四个重要文件:

To echo what is there in the repo, there are four important files:

主要活动

package test.example.fabpop;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.transition.ChangeBounds;
import android.support.transition.Fade;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    FloatingActionButton fab_feather;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fab_feather = (FloatingActionButton) findViewById(R.id.initial_fab_feather);
    }

    public void fabClick(View view) {
        SheetDialog dialogFragment = new SheetDialog();

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        // This seemingly has no effect. I am trying to get it to work.
        transaction.addSharedElement(fab_feather, "transition_name_plane");

        dialogFragment.setSharedElementEnterTransition(new ChangeBounds());
        dialogFragment.setSharedElementReturnTransition(new Fade(Fade.OUT));

        dialogFragment.show(transaction, "frag_tag");
    }
}

activity_main.xml布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="test.example.fabpop.MainActivity">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:orientation="vertical">
        <TextView
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:text="Transition to a BottomSheetDialogFragment that shares this FAB"
            android:textAlignment="center"/>

        <!--  Feather FAB  -->
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/initial_fab_feather"
            android:layout_width="52dp"
            android:layout_height="52dp"
            android:layout_margin="16dp"
            android:layout_gravity="center"
            android:onClick="fabClick"
            android:transitionName="transition_name_feather"
            android:src="@drawable/ic_feather"
            />
    </LinearLayout>


</RelativeLayout>

SheetDialog

package test.example.fabpop;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetDialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class SheetDialog extends BottomSheetDialogFragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        return inflater.inflate(R.layout.dialog_sheet, container, false);
    }
}

dialog_sheet.xml布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!--  Plane FAB  -->
    <android.support.design.widget.FloatingActionButton
        android:id="@+id/final_fab_plane"
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_margin="16dp"
        android:transitionName="transition_name_plane"
        android:src="@drawable/ic_plane"
        />

</LinearLayout>

在一个活动"和一个片段"之间的过渡中是否不可能有一个共享元素?也许只能在活动到活动"或片段到片段"之间进行,而不能跨这两种类型进行?也许这就是为什么我无法使它工作?

Is it not possible to have a shared element on a transition between one Activity and one Fragment? Perhaps is is only possible between Activity to Activity or Fragment to Fragment, but not across the two types? Maybe this is why I cannot get it to work?

更新:

我现在尝试将<item name="android:windowContentTransitions">true</item>添加到应用程序的主题中.

I have now tried adding <item name="android:windowContentTransitions">true</item> to the app's theme.

我现在还在尝试确保两个视图上的两个transitionName值相同.

I have also now tried while ensuring that both transitionName values are the same on both views.

这些都不有助于解决问题.

neither of these have helped to fix the issue.

推荐答案

在我们潜水之前...

让我们首先快速回顾一下android框架如何完成神奇的共享元素转换.

共享元素转换实际上只是android框架的谎言<​​/strong>之一.事实是,当您执行共享元素转换时,实际上并没有在Activities之间共享任何视图,例如,您正在处理两个单独的视图.这是因为每个Activity都有其自己的独立视图树.

A Shared Element Transition is actually just one of android framework's lies. The truth is, when you're doing a Shared Element Transition, you're not actually sharing any view between your Activities, e.i, you're dealing with two separate views. That's because each Activity has its own independent view tree.

假设您试图将由view_a标识的视图从ActivityA转换为ActivityB中的view_b.

Suppose that you're trying to transition a view identified by view_a from ActivityA to a view_b in ActivityB.

该框架的作用是,它首先查找view_a的某些属性,例如<widthheight的大小和xy的位置. c4>.然后,它将这些信息传递给ActivityB,在view_b上应用这些属性,以便在ActivityA关闭时与view_a占据完全相同的位置.之后,该框架通过将view_b动画化为它应该在ActivityB中的动画来开始过渡.这就是如何创建共享视图的错觉.魔术!

What the framework does is that, it first looks for certain properties of your view_a, such as the size (width, height) and the position (x,y) in the ActivityA. It then passes these information to ActivityB, apply these properties on the view_b so that it occupies the exact same spot as view_a when ActivityA gets closed. After that, the framework starts the transition by reverse animating your view_b to what it's supposed to be in ActivityB. And this is how the illusion of the view being shared is created. Magic!

我们可以从上面推断出,在开始任何动画之前,必须确保已经在ActivityB上创建了view_b,否则,这是不可能的.

What we can deduce from above is that before any animation can be started, one has to make sure that view_b has already been created on ActivityB, otherwise, this wouldn't be possible.

调用FragmentTransaction.commit()只会调度您的片段事务(创建包含活动的片段后不会立即创建片段).

Calling FragmentTransaction.commit()will just schedule your fragment transaction (the fragment will NOT be created immediately after its containing Activity has been created).

因此,在您的情况下,创建ActivityB时,您的view_b丢失了(如前所述,这是因为尚未创建其包含的片段).

So, in your case, when your ActivityB is created, your view_b is missing (as explained, that's because its containing fragment hasn't been created yet).

确保在动画开始之前已创建view_b.

Make sure your view_b is created before the animation starts.

为此,您必须找到一种方法来告诉框架不要执行通常的操作,而要等到信号后再创建动画.

For that, you'll have to find a way to tell the framework to not do the usual thing, but to wait instead for your signal before creating the animation.

一种实现此目的的方法是将您的代码更改为与此代码类似的内容:

One way to implement this is to alter your code to be something similar to this one:

class ActivityB extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        // Tell the framework to wait.
        postponeEnterTransition();
    }
}

FragmentB

class FragmentB extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View viewB = getView().findViewById(R.id.view_b);
    sharedview.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
                // Tell the framework to start.
                sharedview.getViewTreeObserver().removeOnPreDrawListener(this);
                getActivity().startPostponedEnterTransition(); 
                return true;
         }
       });
       ...
    }
}

进一步阅读

Activity入门&片段过渡

这篇关于共享元素过渡不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆