android - studio - Las transiciones de elementos compartidos de fragmentos no funcionan con ViewPager
pageradapter android (3)
Mi aplicación contiene una vista que consiste en un ViewPager que consta de un puñado de fragmentos. Cuando hace clic en un elemento en uno de estos fragmentos, el comportamiento esperado es que el elemento compartido (en este caso, una imagen) pase al fragmento que muestra más información sobre el contenido en el que se hizo clic.
Aquí hay un video muy simple de cómo debería verse:
https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-114842.mp4
Esto solo está usando una transición Fragmento-> Fragmento.
El problema surge cuando coloca el fragmento inicial dentro de un ViewPager. Sospecho que esto se debe a que ViewPager utiliza el administrador de fragmentos hijo de su fragmento principal, que es diferente del administrador de fragmentos de la actividad, que maneja la transacción del fragmento. Aquí hay un video de lo que sucede:
https://dl.dropboxusercontent.com/u/97787025/device-2015-06-03-120029.mp4
Estoy bastante seguro de que el problema aquí, como lo expliqué anteriormente, es el administrador de fragmentos secundarios frente al administrador de fragmentos de la actividad. Así es como estoy haciendo la transición:
SimpleFragment fragment = new SimpleFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.am_list_pane, fragment, fragment.getClass().getSimpleName());
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
TransitionSet enterTransition = new TransitionSet();
enterTransition.addTransition(new ChangeBounds());
enterTransition.addTransition(new ChangeClipBounds());
enterTransition.addTransition(new ChangeImageTransform());
enterTransition.addTransition(new ChangeTransform());
TransitionSet returnTransition = new TransitionSet();
returnTransition.addTransition(new ChangeBounds());
returnTransition.addTransition(new ChangeClipBounds());
returnTransition.addTransition(new ChangeImageTransform());
returnTransition.addTransition(new ChangeTransform());
fragment.setSharedElementEnterTransition(enterTransition);
fragment.setSharedElementReturnTransition(returnTransition);
transaction.addSharedElement(iv, iv.getTransitionName());
}
transaction.addToBackStack(fragment.getClass().getName());
transaction.commit();
Esto funciona bien cuando el administrador de fragmentos de la actividad administra ambos fragmentos, pero cuando cargo un ViewPager como este:
ViewPager pager = (ViewPager) view.findViewById(R.id.pager);
pager.setAdapter(new Adapter(getChildFragmentManager()));
La actividad no administra a los hijos de ViewPager y ya no funciona.
¿Es esto un descuido del equipo de Android? ¿Hay alguna manera de lograr esto? Gracias.
En la actividad
supportPostponeEnterTransition();
Y cuando se cargan sus fragmentos (intente sincronizarlos, tal vez con EventBus o lo que sea)
startPostponedEnterTransition();
Consulte esta muestra
He estado golpeando mi cabeza contra la pared con este recientemente. Todo lo que quería era un Fragmento en un ViewPager para lanzar otro Fragmento con una agradable transición de elemento compartido de tipo de tarjeta en expansión. Ninguna de las sugerencias anteriores funcionó para mí, así que decidí intentar iniciar una Actividad con el estilo de un Diálogo:
<style name="AppTheme.CustomDialog" parent="MyTheme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
Luego, para lanzar la Actividad desde el Fragmento:
Intent intent = new Intent(getContext(), MyDialogActivity.class);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(getActivity(),
Pair.create(sharedView, "target_transition"));
ActivityCompat.startActivity(getActivity(), intent, options.toBundle());
En el diseño Fragmento, coloque un android: transition_name en sharedView y en el diseño Activity tenga android: transition_name = "target_transition" (igual que el segundo argumento Pair.create ()).
Probablemente ya haya encontrado una respuesta a esto, pero en caso de que no lo haya hecho, esto es lo que hice para solucionarlo después de unas horas de rascarme la cabeza.
Creo que el problema es una combinación de dos factores:
-
Los
Fragments
enViewPager
cargan con un retraso, lo que significa que la actividad regresa mucho más rápido que sus fragmentos que están contenidos dentro deViewPager
-
Si eres como yo, los fragmentos secundarios de tu
ViewPager
son probablemente del mismo tipo. Esto significa que todos comparten el mismo nombre de transición (si los ha configurado en su diseño xml), a menos que los configure en código y solo lo configure una vez, en el fragmento visible .
Para solucionar estos dos problemas, esto es lo que hice:
1. Arreglando el problema de carga demorada:
Dentro de su actividad (la que contiene
ViewPager
), agregue esta línea después de
super.onCreate()
y antes de
setContentView()
:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCompat.postponeEnterTransition(this); // This is the line you need to add
setContentView(R.layout.feeds_content_list_activity);
...
}
2. Solucionando el problema con múltiples fragmentos con el mismo nombre de transición:
Ahora hay bastantes maneras de hacerlo, pero esto es lo que terminé dentro de mi actividad "detallada", es decir, la actividad que contiene
ViewPager
(en
onCreate()
pero puede hacerlo en cualquier lugar realmente):
_viewPager.setAdapter(_sectionsPagerAdapter);
_viewPager.setCurrentItem(position);
...
...
_pagerAdapter.getItem(position).setTransitionName(getResources().getString(R.string.transition_contenet_topic));
ViewPager
tener cuidado, ya que es posible que la
Activity
aún no esté adjunta a su fragmento de
ViewPager
por lo que es más fácil simplemente pasar el nombre de transición de la actividad al fragmento si lo está cargando desde un recurso
La implementación real es tan simple como espera:
public void setTransitionName(String transitionName) {
_transitionName = transitionName;
}
Luego, dentro de
onViewCreated()
su fragmento, agregue esta línea:
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
...
if (_transitionName != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
setTransitionNameLollipop();
}
...
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setTransitionNamesLollipop() {
_imgTopic.setTransitionName(_transitionName);
}
La última pieza del rompecabezas es averiguar cuándo su fragmento está completamente cargado y luego llamar a
ActivityCompat.startPostponedEnterTransition(getActivity());
.
En mi caso, mis fragmentos no se cargaron completamente hasta más tarde, ya que estoy cargando la mayoría de las cosas del hilo de la interfaz de usuario, lo que significa que tuve que encontrar una manera de llamar a esto cuando todo estaba cargado, pero si ese no es tu caso, puedes llamar a esto justo después de llamar a
setTransitionNameLollipop()
.
El problema con este enfoque es que la transición de salida puede no funcionar a menos que tenga mucho cuidado y restablezca el nombre de transición en el fragmento "visible" justo antes de
exit
la actividad para navegar hacia atrás.
Eso se puede hacer fácilmente así:
-
Escuche el cambio de página en su
ViewPager
- Elimine los nombres de transición tan pronto como su fragmento esté fuera de la vista.
- Establezca los nombres de transición en el fragmento visible.
-
En lugar de llamar a
finish()
, llame aActivityCompat.finishAfterTransition(activity);
Esto puede volverse muy complejo muy pronto si la transición de regreso necesita pasar a un
RecyclerView
que fue mi caso.
Para eso, hay una respuesta mucho mejor proporcionada por @Alex Lockwood aquí:
ViewPager Fragments - Shared Element Transitions
que tiene un código de ejemplo muy bien escrito (aunque mucho más complicado que lo que acabo de escribir) aquí:
https://github.com/alexjlockwood/activity-transitions/tree/master/app/src/main/java/com/alexjlockwood/activity/transitions
En mi caso, no tuve que ir tan lejos como para implementar su solución y la solución anterior que publiqué funcionó para mi caso.
En caso de que tenga varios elementos compartidos, estoy seguro de que puede descubrir cómo extender los métodos para atenderlos.