我有一个更大的项目,当用户在应用程序中导航时,我需要在片段之间转换时应用一些动画。
到目前为止,我在setCustomAnimation
上使用了FragmentTransaction
方法,并且它按预期工作得很好,但是在需要动画视图时它非常有限。
所以我决定继续使用Transition API。好消息,它是支持库的一部分(通过AndroidX),sharedElement
与transitionName
也被向后移植。所以只有一组代码可以编写而且没有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>
说到碎片,就像我说的那样,我严格要求,所以我有两个碎片,即FragmentOne
和FragmentTwo
。
两个片段都有类似的布局:
<?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版本)来动画这两个文本之间的过渡。
FragmentOne
到FragmentTwo
时,文本滑动/向底部移动以下是这两个片段的代码:
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();
}
});
}
}
你去吧这里没有额外的/花哨的代码。
简而言之:
addSharedElement
上使用FragmentTransaction
。该名称与MainActivity
中声明的静态变量相同ViewCompat#setTransitionName
将转换名称设置为我的共享视图,而我的模拟器运行Android 9 Pie。我哪里弄错了?为什么没有过渡?
我注意到我的片段布局(由Android Studio在创建片段时生成)的TextViews
使用match_parent
作为宽度和高度。因此,我认为没有太多的滑动/移动要做,因为两个视图具有相同的边界(匹配相同大小的父级)。
我用更好的布局更新了上面的帖子,但结果完全一样。我甚至添加了一些背景来正确地查看视图边界,并直接在XML中设置转换名称,尽管这样做不是向后兼容的,但我是为了测试而做的。