android - programacion - Transición de elemento compartido no funciona
programacion android pdf 2018 (3)
Antes de bucear en ...
Primero, destacemos algunos puntos sobre cómo el marco de Android hace la transición del elemento compartido mágico.
Una transición de elementos compartidos es solo una de las mentiras de Android Framework Cuando realiza una transición de elemento compartido, en realidad no está compartiendo ninguna vista entre sus actividades, ei, cada actividad tiene un árbol de vista independiente.
Supongamos que está intentando realizar la transición de un element
identificado por element1
de Activity1
a element2
en Activity2
.
Lo que hace el marco es que busca cierta información como el tamaño ( width
, height
) y la posición ( x
, y
) de su elemento1 en la Activity1
. Luego pasa esta información a la Activity2
, aplíquela en el element2
y comienza la transición de la actividad al animar su element2
que crea esta ilusión del elemento que se comparte.
Sin embargo, esto requiere que se cree la Activity2
que se encuentre la view
correspondiente al element2
antes de poder iniciar cualquier animación.
En el caso de usar un Fragment
, llamar a FragmentTransaction.commit()
solo programará su transacción de fragmento (el fragmento no se creará de inmediato), por lo que cuando se crea su element2
falta su element2
(como se explicó, eso se debe a que su fragmento que contiene no tiene). No se ha creado todavía).
Solución
Asegúrate de que tu element2
esté creado antes de que comience la animación. Por lo tanto, tendrá que encontrar una manera de decirle al marco que no haga lo habitual, pero en lugar de eso, espere su señal antes de crear la animación.
Una forma de hacerlo es alterar su código para que sea algo similar a este:
Actividad2
class Activity2 extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
// Tell the framework to wait.
postponeEnterTransition();
}
}
Fragmento 2
class Fragment2 extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View element2 = getView().findViewById(R.id.element);
sharedview.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
// Tell the framework to start.
sharedview.getViewTreeObserver().removeOnPreDrawListener(this);
getActivity().startPostponedEnterTransition();
return true;
}
});
...
}
}
Otras lecturas
He hecho un proyecto github con sólo el problema. Puede verlo / clonarlo / construirlo desde aquí: https://git.io/vMPqb
Estoy tratando de obtener elementos compartidos trabajando para una transición de Fragmento.
Hay dos FAB en el proyecto: Feather y Plane. La pluma y el plano son elementos compartidos. Cuando se hace clic en Feather, se abre el SheetDialog, y Feather debería animarse en el cuadro de diálogo Plano. No lo hace en este momento, y estoy tratando de determinar por qué.
Puede que valga la pena tener en cuenta que estoy ejecutando esto en la API 24, por lo que los problemas con las transiciones que no son compatibles con la versión 21 no son el problema.
¿Alguien puede decirme por qué las transiciones de elementos compartidos no funcionan?
Para hacer eco de lo que hay en el repositorio, hay cuatro archivos importantes:
Actividad principal
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 Layout
<?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 Layout
<?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>
¿No es posible tener un elemento compartido en una transición entre una Actividad y un Fragmento? ¿Quizás solo es posible entre Actividad a Actividad o Fragmento a Fragmento, pero no a través de los dos tipos? Tal vez es por eso que no puedo hacerlo funcionar?
Actualizar:
Ahora he intentado agregar <item name="android:windowContentTransitions">true</item>
al <item name="android:windowContentTransitions">true</item>
de la aplicación.
También he intentado ahora asegurándome de que los dos valores de transición son iguales en ambas vistas.
Ninguno de estos ha ayudado a solucionar el problema.
Lo que estás buscando es este ejemplo: https://github.com/hujiaweibujidao/FabDialogMorph . Tenga en cuenta que lo que está tratando de lograr no es una transición estándar de Android, debe crear su propia transición de transformación basada en la transición de ChangeBounds
. Originalmente, se ha mostrado en Plaid , gracias a Nick Butcher por eso, por lo que puede consultar más consejos y antecedentes.
Sólo citando los documentos de Android :
Iniciar una actividad con un elemento compartido.
- Asigne un nombre común a los elementos compartidos en ambos diseños con el atributo android: transitionName.
Por lo que veo, ambos XML no comparten el mismo android: transitionName .
Intente cambiar ambos android: transitionName en el diseño XML (activity_main.xml & dialog_sheet.xml) a una misma cadena, por ejemplo: transition_plane_feather
Yo mismo no he probado los códigos, pero creo que ese podría ser un buen punto de partida.
Consejo de bonificación
Si planea implementar completamente el Diseño de materiales sin compatibilidad con niveles de API más bajos (antes de Lollipop), le recomiendo que consulte una muestra realizada por un diseñador de UI / UX de Google: Plaid
Además, vea el excelente video complementario de YouTube para esa muestra: https://www.youtube.com/watch?v=EjTJIDKT72M
Le muestra algunos de los mejores trucos y prácticas que puede utilizar para implementar completamente el Diseño de materiales, así como las transiciones de elementos compartidos.