Transición de fragmentos en Android
Las transiciones de actividades y fragmentos en Lollipop (Android 5.0) se basan en algunas características de Android relativamente nuevas, llamadas transiciones. Introducido en KitKat, el framework de transiciones proporciona un conjunto conveniente de API para animar entre diferentes estados de UI en una aplicación. Este framework se construye alrededor de dos conceptos clave: escenas y transiciones. Una escena define un estado determinado de la UI de la aplicación, mientras que una transición define el cambio animado entre dos escenas.
Cuando una escena cambia, la transición tiene dos responsabilidades principales:
- Capturar el estado de cada vista en las escenas inicial y final.
- Crear un Animator (animador) basado en las diferencias de las vistas que necesitan animarse de una escena a otra.
Ejemplo
Este ejemplo explica cómo usar las transiciones de fragmentos para crear animaciones personalizadas. Comencemos siguiendo los pasos a continuación:
| Pasos | Descripción |
|---|---|
| 1 | Usa Android Studio para crear una aplicación de Android, llamada Fragment Custom Animation, con el paquete cn.uprogrammer.fragmentcustomanimation. |
| 2 | Modifica el archivo res/layout/activity_main.xml y agrega un TextView. |
| 3 | Crea el archivo de diseño fragment_stack.xml en res/layout/, define la etiqueta de fragment y la etiqueta de botón. |
| 4 | Crea el subdirectorio anim bajo res/ y agrega fragment_slide_left.xml, fragment_slide_left_exit.xml, fragment_slide_right_exit.xml y fragment_slide_left_enter.xml. |
| 5 | En MainActivity.java necesitas agregar la pila de fragmentos, el administrador de fragmentos y onCreateView(). |
| 6 | Inicia el emulador de Android para ejecutar la aplicación y verifica los resultados de los cambios realizados en la aplicación. |
A continuación se muestra el contenido del archivo res/layout/activity_main.xml, que contiene FrameLayout y un botón.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/fragment1"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<Button
android:id="@+id/new_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="添加新碎片" />
</LinearLayout>
A continuación se muestra el archivo res/anim/fragment_stack.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">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"/>
</LinearLayout>
A continuación se muestra el contenido del archivo res/animator/fragment_slide_left_enter.xml, que contiene métodos setter y etiquetas de objetos animator.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="100dp" android:valueTo="0dp"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime" />
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="0.0" android:valueTo="1.0"
android:valueType="floatType"
android:propertyName="alpha"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
A continuación se muestra el contenido del archivo res/animator/fragment_slide_left_exit.xml, que contiene métodos setter y etiquetas de objetos animator.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="0dp" android:valueTo="-100dp"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime" />
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="1.0" android:valueTo="0.0"
android:valueType="floatType"
android:propertyName="alpha"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
A continuación se muestra el contenido del archivo res/animator/fragment_slide_right_enter.xml, que contiene métodos setter y etiquetas de objetos animator.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="-100dp" android:valueTo="0dp"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime" />
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="0.0" android:valueTo="1.0"
android:valueType="floatType"
android:propertyName="alpha"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
A continuación se muestra el contenido del archivo res/animator/fragment_slide_right_exit.xml, que contiene métodos setter y etiquetas de objetos animator.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="0dp" android:valueTo="100dp"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime" />
<objectAnimator
android:interpolator="@android:interpolator/decelerate_quint"
android:valueFrom="1.0" android:valueTo="0.0"
android:valueType="floatType"
android:propertyName="alpha"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
A continuación se muestra el contenido del archivo src/cn.uprogrammer.fragmentcustomanimation/MainActivity.java, que contiene el listener del botón, CountingFragment y onCreateView():
package cn.uprogrammer.fragmentcustomanimation;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
/**
* 演示在碎片事务中使用自定义动画.
*/
public class MainActivity extends Activity {
int mStackLevel = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.new_fragment);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
addFragmentToStack();
}
});
if (savedInstanceState == null) {
// 添加初始碎片
Fragment newFragment = CountingFragment.newInstance(mStackLevel);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.fragment1, newFragment).commit();
}
else
{
mStackLevel = savedInstanceState.getInt("level");
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("level", mStackLevel);
}
void addFragmentToStack() {
mStackLevel++;
// 实例化新的碎片
Fragment newFragment = CountingFragment.newInstance(mStackLevel);
// 添加碎片到活动,并将其放入后退栈中
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.animator.fragment_slide_left_enter,
R.animator.fragment_slide_left_exit,
R.animator.fragment_slide_right_enter,
R.animator.fragment_slide_right_exit);
ft.replace(R.id.fragment1, newFragment);
ft.addToBackStack(null);
ft.commit();
}
public static class CountingFragment extends Fragment {
int mNum;
/**
* 创建CountingFragment的实例,提供"num"作为参数
*/
static CountingFragment newInstance(int num) {
CountingFragment f = new CountingFragment();
Bundle args = new Bundle();
args.putInt("num", num);
f.setArguments(args);
return f;
}
/**
* 在创建时,获取实例的number参数.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mNum = getArguments() != null ? getArguments().getInt("num") : 1;
}
/**
* 碎片的界面仅包含一个TextView,用于显示number
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_stack, container, false);
View tv = v.findViewById(R.id.text);
((TextView)tv).setText("Fragment #" + mNum);
tv.setBackgroundDrawable(getResources().getDrawable(android.R.drawable.gallery_thumb));
return v;
}
}
}
A continuación se muestra el contenido del archivo AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.uprogrammer.fragmentcustomanimation"
android:versionCode="1"
android:versionName="1.0" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Ejecutemos la aplicación Fragment Custom Animation que acabamos de modificar. Supongo que ya has creado un AVD al instalar el entorno. Abre el archivo de actividad de tu proyecto y haz clic en el
icono de la barra de herramientas para ejecutar la aplicación en Android Studio. Android Studio instala la aplicación en el AVD y la inicia. Si todo sale bien, se mostrará lo siguiente en la ventana del emulador:
