android - programacion - ¿Cómo comenzar la transición de elementos compartidos usando Fragments?
manual de programacion android pdf (7)
Busqué SharedElement en fragmentos y encuentro un código fuente muy útil en GitHub.
1.primero debe definir el nombre de transición para sus objetos (como ImageView) en ambos diseños de Fragmentos (agregamos un botón en el fragmento A para manejar el evento de clic):
fragmento A :
<ImageView
android:id="@+id/fragment_a_imageView"
android:layout_width="128dp"
android:layout_height="96dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="80dp"
android:scaleType="centerCrop"
android:src="@drawable/gorilla"
android:transitionName="@string/simple_fragment_transition />
<Button
android:id="@+id/fragment_a_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="24dp"
android:text="@string/gorilla" />
fragmento B:
<ImageView
android:id="@+id/fragment_b_image"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="centerCrop"
android:src="@drawable/gorilla"
android:transitionName="@string/simple_fragment_transition" />
- Luego, debe escribir este código en su archivo de transición en el Directorio de transición (si no tiene este Directorio, cree One: res> new> Android Resource Directory> Resource Type = transition> name = change_image_transform):
change_image_transform.xml:
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
</transitionSet>
- En el último paso, debe completar los códigos en Java:
fragmento A:
public class FragmentA extends Fragment {
public static final String TAG = FragmentA.class.getSimpleName();
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final ImageView imageView = (ImageView) view.findViewById(R.id.fragment_a_imageView);
Button button = (Button) view.findViewById(R.id.fragment_a_btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
getFragmentManager()
.beginTransaction()
.addSharedElement(imageView, ViewCompat.getTransitionName(imageView))
.addToBackStack(TAG)
.replace(R.id.content, new FragmentB())
.commit();
}
});
}
}
fragmento B:
public class FragmentB extends Fragment {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setSharedElementEnterTransition(TransitionInflater.from(getContext()).inflateTransition(android.R.transition.move));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_b, container, false);
}
}
no olvides mostrar tu fragmento "A" en tu actividad:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportFragmentManager()
.beginTransaction()
.add(R.id.content, new SimpleFragmentA())
.commit();
}
fuente: https://github.com/mikescamell/shared-element-transitions
Estoy tratando de implementar transiciones entre fragmentos que tienen "elementos compartidos" como se describe en las nuevas especificaciones de diseño de materiales. El único método que puedo encontrar es ActivityOptionsCompat.makeSceneTransitionAnimation , que creo que funciona solo en Activity. He estado buscando esta misma funcionalidad pero con / para fragmentos.
Esto debería ser un comentario a la respuesta aceptada, ya que no puedo hacer ningún comentario al respecto.
La respuesta aceptada (por WindsurferOak y ar34z) funciona, excepto por un problema "menor" que causó una excepción de puntero nulo al navegar con BackStack.
Parece que se debe llamar a
setSharedElementReturnTransition()
en el fragmento de destino en lugar del fragmento original.
Entonces en lugar de:
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
debería ser
fragment.setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
Estoy publicando esto como respuesta, ya que soy nuevo aquí y no puedo comentar.
Las transiciones de fragmentos de elementos compartidos funcionan con ListViews, siempre que las vistas de origen y destino tengan el mismo (y único) nombre de transición.
Si hace que su adaptador de vista de lista establezca nombres de transición únicos para las vistas que desea (por ejemplo, alguna identificación de elemento constante + específica) y también cambie su fragmento de detalle para establecer los mismos nombres de transición a las vistas de destino en tiempo de ejecución (onCreateView), las transiciones realmente funcionan !
La clave es usar una transacción personalizada con
transaction.addSharedElement(sharedElement, "sharedImage");
Transición de elementos compartidos entre dos fragmentos
En este ejemplo, uno de los dos
ImageViews
diferentes se debe traducir del
ChooserFragment
al
DetailFragment
.
En el diseño
ChooserFragment
necesitamos los atributos únicos de nombre de
transitionName
:
<ImageView
android:id="@+id/image_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_first"
android:transitionName="fistImage" />
<ImageView
android:id="@+id/image_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_second"
android:transitionName="secondImage" />
En la clase
ChooserFragments
, necesitamos pasar la
View
que se hizo clic y una ID a la
Activity
principal que maneja el reemplazo de los fragmentos (necesitamos la ID para saber qué recurso de imagen mostrar en el
DetailFragment
).
Cómo pasar información a la actividad de un padre en detalle seguramente está cubierto en otra documentación.
view.findViewById(R.id.image_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 1);
}
}
});
view.findViewById(R.id.image_second).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mCallback != null) {
mCallback.showDetailFragment(view, 2);
}
}
});
En
DetailFragment
,
ImageView
del elemento compartido también necesita el atributo de
transitionName
único.
<ImageView
android:id="@+id/image_shared"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:transitionName="sharedImage" />
En el método
onCreateView()
del
DetailFragment
, tenemos que decidir qué recurso de imagen se debe mostrar (si no lo hacemos, el elemento compartido desaparecerá después de la transición).
public static DetailFragment newInstance(Bundle args) {
DetailFragment fragment = new DetailFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_detail, container, false);
ImageView sharedImage = (ImageView) view.findViewById(R.id.image_shared);
// Check which resource should be shown.
int type = getArguments().getInt("type");
// Show image based on the type.
switch (type) {
case 1:
sharedImage.setBackgroundResource(R.drawable.ic_first);
break;
case 2:
sharedImage.setBackgroundResource(R.drawable.ic_second);
break;
}
return view;
}
La
Activity
principal está recibiendo las devoluciones de llamada y maneja el reemplazo de los fragmentos.
@Override
public void showDetailFragment(View sharedElement, int type) {
// Get the chooser fragment, which is shown in the moment.
Fragment chooserFragment = getFragmentManager().findFragmentById(R.id.fragment_container);
// Set up the DetailFragment and put the type as argument.
Bundle args = new Bundle();
args.putInt("type", type);
Fragment fragment = DetailFragment.newInstance(args);
// Set up the transaction.
FragmentTransaction transaction = getFragmentManager().beginTransaction();
// Define the shared element transition.
fragment.setSharedElementEnterTransition(new DetailsTransition());
fragment.setSharedElementReturnTransition(new DetailsTransition());
// The rest of the views are just fading in/out.
fragment.setEnterTransition(new Fade());
chooserFragment.setExitTransition(new Fade());
// Now use the image''s view and the target transitionName to define the shared element.
transaction.addSharedElement(sharedElement, "sharedImage");
// Replace the fragment.
transaction.replace(R.id.fragment_container, fragment, fragment.getClass().getSimpleName());
// Enable back navigation with shared element transitions.
transaction.addToBackStack(fragment.getClass().getSimpleName());
// Finally press play.
transaction.commit();
}
Sin olvidar: la
Transition
sí.
Este ejemplo mueve y escala el elemento compartido.
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class DetailsTransition extends TransitionSet {
public DetailsTransition() {
setOrdering(ORDERING_TOGETHER);
addTransition(new ChangeBounds()).
addTransition(new ChangeTransform()).
addTransition(new ChangeImageTransform());
}
}
Los elementos compartidos funcionan con Fragmentos, pero hay algunas cosas a tener en cuenta:
-
No intente configurar
sharedElementsTransition
enonCreateView
de su Fragment.onCreate
definirlos al crear una instancia de su Fragmento o enonCreate
. -
Tome nota de la documentación oficial sobre las posibles animaciones para las transiciones de entrada / salida y sharedElementTransition. Ellos no son los mismos.
-
Prueba y error :)
Tuve el mismo problema pero lo hice funcionar agregando un nuevo fragmento de otro fragmento. El siguiente enlace es muy útil para comenzar con esto: https://developer.android.com/training/material/animations.html#Transitions
El siguiente es mi código que funciona.
Estoy animando un
ImageView
de un fragmento a otro.
Asegúrese de que la
View
que desea animar tenga el mismo
android:transitionName
en ambos fragmentos.
El otro contenido realmente no importa.
Como prueba, puede copiar esto en sus archivos xml de diseño. Asegúrate de que la imagen exista.
<ImageView
android:transitionName="MyTransition"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/test_image" />
Luego tengo 1 archivo en mi carpeta
res/transition
, llamado
change_image_transform.xml
.
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeImageTransform />
</transitionSet>
Ahora puedes comenzar. Digamos que tiene el Fragmento A que contiene la imagen y desea agregar el Fragmento B.
Ejecute esto en el Fragmento A:
@Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.product_detail_image_click_area:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setSharedElementReturnTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
setExitTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));
// Create new fragment to add (Fragment B)
Fragment fragment = new ImageFragment();
fragment.setSharedElementEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(R.transition.change_image_transform));
fragment.setEnterTransition(TransitionInflater.from(getActivity()).inflateTransition(android.R.transition.explode));
// Our shared element (in Fragment A)
mProductImage = (ImageView) mLayout.findViewById(R.id.product_detail_image);
// Add Fragment B
FragmentTransaction ft = getFragmentManager().beginTransaction()
.replace(R.id.container, fragment)
.addToBackStack("transaction")
.addSharedElement(mProductImage, "MyTransition");
ft.commit();
}
else {
// Code to run on older devices
}
break;
}
}