Fragment Transition API,支持库(14+)没有进行任何转换

问题描述 投票:1回答:1

我有一个更大的项目,当用户在应用程序中导航时,我需要在片段之间转换时应用一些动画。

到目前为止,我在setCustomAnimation上使用了FragmentTransaction方法,并且它按预期工作得很好,但是在需要动画视图时它非常有限。

所以我决定继续使用Transition API。好消息,它是支持库的一部分(通过AndroidX),sharedElementtransitionName也被向后移植。所以只有一组代码可以编写而且没有SDK INT检查要做!

但是我失败了,因为我的项目很大,我决定创建一个新的,非常简单,直截了当,看看我是否正确。

但我没有做对!所以,在这一点上,我想分享这个非常简单的项目的代码。如果有人能理解为什么我没有获得过渡,我将非常感激。

无论如何,代码:

main activity.Java

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    public final static String TRANSITION_NAME = "test_transition_name";


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

        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fragment_holder, new FragmentOne(), "FragmentOne")
                .commit();
    }
}

正如你所看到的,没什么,我立刻触发了显示我的第一个片段(FragmentOne)的过程。

它的布局,无论如何:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/fragment_holder"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

</androidx.constraintlayout.widget.ConstraintLayout>

说到碎片,就像我说的那样,我严格要求,所以我有两个碎片,即FragmentOneFragmentTwo

两个片段都有类似的布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FragmentOne">

    <!-- TODO: Update blank fragment layout -->
   <TextView
        android:id="@+id/text_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="40sp"
        android:textStyle="bold"
        android:gravity="top|center_horizontal"
        android:textColor="@android:color/white"
        android:background="@android:color/black"
        android:transitionName="test_transition_name"
        android:text="Hello From Fragment ONE" />

</FrameLayout>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FragmentTwo">

    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/text_two"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="40sp"
        android:textStyle="bold"
        android:gravity="bottom|center_horizontal"
        android:layout_gravity="bottom"
        android:textColor="@android:color/white"
        android:background="@android:color/black"
        android:transitionName="test_transition_name"
        android:text="Hello from fragment TWO" />

</FrameLayout>

正如您所看到的,这两个片段布局之间的唯一区别是文本内容(我做得更大)和引力。在FragmentOne中,文本位于布局的顶部,而它位于FragmentTwo的底部。没有什么可以直截了当的。

此时,我的目标是使用Transition API(Android X版本)来动画这两个文本之间的过渡。

  1. 当从FragmentOneFragmentTwo时,文本滑动/向底部移动
  2. 返回时,文本向上/向上移动(反向)。

以下是这两个片段的代码:

FragmentOne

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;


/**
 * A simple {@link Fragment} subclass.
 */
public class FragmentOne extends Fragment {


    public FragmentOne() {
        // Required empty public constructor
    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setSharedElementReturnTransition(new AutoTransition());
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_one, container, false);
    }


    @Override
    public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        ViewCompat.setTransitionName(view.findViewById(R.id.text_one), MainActivity.TRANSITION_NAME);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager()
                        .beginTransaction()
                        .addSharedElement(view.findViewById(R.id.text_one), MainActivity.TRANSITION_NAME)
                        .replace(R.id.fragment_holder, new FragmentTwo(), "FragmentTwo")
                        .addToBackStack("FragmentTwo")
                        .commit();
            }
        });
    }
}

FragmentTwo

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.transition.AutoTransition;
import androidx.transition.Transition;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
 * A simple {@link Fragment} subclass.
 */
public class FragmentTwo extends Fragment {


    public FragmentTwo() {
        // Required empty public constructor
    }


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setSharedElementEnterTransition(new AutoTransition());
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment__two, container, false);
    }


    @Override
    public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        ViewCompat.setTransitionName(view.findViewById(R.id.text_two), MainActivity.TRANSITION_NAME);

        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager().popBackStack();
            }
        });
    }
}

你去吧这里没有额外的/花哨的代码。

简而言之:

  1. 我在我的addSharedElement上使用FragmentTransaction。该名称与MainActivity中声明的静态变量相同
  2. 正如我所说,我想一直使用Android X库,因此所有类都来自Android X包,我甚至使用ViewCompat#setTransitionName将转换名称设置为我的共享视图,而我的模拟器运行Android 9 Pie。

我哪里弄错了?为什么没有过渡?

[更新1]

我注意到我的片段布局(由Android Studio在创建片段时生成)的TextViews使用match_parent作为宽度和高度。因此,我认为没有太多的滑动/移动要做,因为两个视图具有相同的边界(匹配相同大小的父级)。

我用更好的布局更新了上面的帖子,但结果完全一样。我甚至添加了一些背景来正确地查看视图边界,并直接在XML中设置转换名称,尽管这样做不是向后兼容的,但我是为了测试而做的。

android android-fragments android-transitions shared-element-transition
1个回答
0
投票

我从你的代码构建项目。动画效果非常完美。我唯一注意到的事情 - 在FragmentOne你没有添加

import androidx.transition.AutoTransition; 

那么也许你在那里使用android.transition.AutoTransition课程。也许错误就在那里。

它也可以在xml文件中没有android:transitionName行(因为你几乎设置它通过ViewCompat.setTransitionName)所以一切都应该向后兼容。

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.