1. Antes de comenzar
Los dispositivos Android están disponibles en varias formas, tamaños y factores de forma. Diseña tu app para que se ejecute en diferentes tipos de dispositivos, desde dispositivos con pantallas pequeñas hasta otros con pantallas más grandes. Si bien es posible que los desarrolladores que crean apps listas para la producción admitan Android Wear, Android Auto y Android TV, esos temas no se tratan en este curso. Si tu app admite la más amplia variedad de pantallas, podrás hacer que esté disponible para la mayor cantidad posible de usuarios con diferentes dispositivos.
Tu app debe tener un diseño flexible. En lugar de definir un diseño con dimensiones rígidas para una relación de aspecto y un tamaño de pantalla determinados, tu diseño debería poder adaptarse correctamente a varios tamaños y orientaciones de pantalla. El mismo principio se aplica cuando tu app se ejecuta en un dispositivo plegable, en el que el tamaño de la pantalla y la relación de aspecto pueden cambiar durante la ejecución. Al final de este codelab, te daremos una introducción breve a los dispositivos plegables.
Requisitos previos
- Descargar código en Android Studio y ejecutarlo
- Conocer los componentes de la arquitectura de Android
ViewModel
yLiveData
- Tener conocimientos básicos de los componentes de Navigation
Qué aprenderás
- Cómo agregar
SlidingPaneLayout
a tu app
Qué compilarás
- Actualiza la app de Deportes para adaptarla a las pantallas grandes.
Requisitos
- Una computadora que tenga Android Studio instalado
- Código de inicio para la app de Deportes.
Cómo descargar el código de partida para este codelab
Este codelab te brinda el código de partida para que lo extiendas con funciones que se explicaron en este codelab. El código de partida puede contener código que te resulte familiar de codelabs anteriores, así como código que no conozcas y que aprenderás en codelabs posteriores.
A fin de obtener el código de este codelab desde GitHub y abrirlo en Android Studio, haz lo siguiente:
- Inicia Android Studio.
- En la ventana Welcome to Android Studio, haz clic en Get from VCS.
- En el diálogo Get from Version Control, asegúrate de que esté seleccionado Git para Version control.
- Pega la URL del código proporcionado en el cuadro URL.
- Si lo prefieres, cambia el Directorio a uno diferente al predeterminado sugerido.
- Haz clic en Clonar. Android Studio comenzará a recuperar tu código.
- Espera a que se abra Android Studio.
- Selecciona el módulo correcto para tu activador de codelab, tu app o tu código de solución.
- Haz clic en el botón Run para compilar y ejecutar el código.
2. Mira el video con instrucciones para compilar (opcional)
Si quieres ver cómo uno de los instructores del curso completa el codelab, reproduce el siguiente video.
Se recomienda expandir el video a pantalla completa (con el ícono en la esquina inferior derecha del video) para que puedas ver Android Studio y el código con mayor claridad.
Este paso es opcional. También puedes omitir el video y comenzar con las instrucciones del codelab de inmediato.
3. Descripción general de la app de inicio
La app de Deportes consta de dos pantallas. En la primera se muestra la lista de deportes. El usuario puede seleccionar un artículo de deportes en particular y se muestra la segunda pantalla. En este última, que es de detalles, aparecen noticias de los deportes seleccionados. Se muestra el texto del marcador de posición para simplificar la implementación.
Explicación del código de inicio
El código de partida que descargaste ya incluye los diseños de pantalla de la lista y pantalla de detalles listos. En esta ruta de aprendizaje, solo te enfocarás en lograr que tu app se adapte a pantallas grandes. Usarás SlidingPaneLayou
para aprovechar la pantalla grande. Aquí encontrarás una breve explicación de algunos de los archivos para comenzar.
fragment_sports_list.xml
- Abre
res/layout/fragment_sports_list.xml
en la vista Design. - Contiene el diseño de la primera pantalla de tu app que es la lista de deportes.
- Este diseño consiste en una vista Recyclerview en la que se muestra una lista de noticias sobre deportes.
sports_list_item.xml
- Abre
res/layout/sports_list_item.xml
en la vista Design. - Contiene el diseño de cada elemento de la vista Recyclerview.
- Este diseño contiene una imagen en miniatura del deporte, el título News y el texto del marcador de posición de una noticia breve sobre deportes.
fragment_sports_news.xml
- Abre
res/layout/fragment_sports_news.xml
en la vista Design. - Contiene el diseño de la segunda pantalla de tu app. Esta pantalla se muestra cuando el usuario selecciona un deporte desde la vista Recyclerview.
- Este diseño contiene el banner de una imagen del deporte y el texto del marcador de posición de las noticias sobre deportes.
main_activity.xml y content_main.xml
Ambos definen el diseño de la actividad principal con un solo fragmento.
navigation/nav_graph.xml
El gráfico de navegación contiene dos destinos, uno para listas de deportes y otro para noticias de deportes.
carpeta res/values
Estás familiarizado con los archivos de recursos de esta carpeta.
colors.xml
contiene los colores del tema que se usaron en la app.strings.xml
contiene todas las strings que necesita tu app.themes.xml
contiene la personalización de la IU completada para tu app.
MainActivity.kt
Contiene el código predeterminado que genera la plantilla para establecer la vista de contenido de la actividad como main_activity.xml
. Se anula el método onSupportNavigateUp()
para controlar la navegación hacia arriba predeterminada desde la barra de la aplicación.
model/Sport.kt
Se trata de una clase de datos que contiene los datos que se mostrarán en cada fila de la lista de deportes Recyclerview.
data/SportsData.kt
Este archivo contiene una función llamada getSportsData()
, que muestra un objeto ArrayList
prepropagado con datos de deportes codificados.
SportsViewModel.kt
Este es el ViewModel
compartido para la app. SportsListFragment
comparte el ViewModel
, la primera pantalla con la lista de deportes, y NewsDetailsFragment
, la segunda pantalla con las noticias sobre deportes detalladas.
- La propiedad
_currentSport
es del tipoMutableLiveData,
, que almacena el deporte actual que seleccionó el usuario. La propiedadcurrentSport
es la propiedad de copia de seguridad de_currentSport
y se expone como la versión pública de solo lectura de otras clases. - La propiedad
_sportsData
contiene la lista de datos sobre deportes. Al igual que la propiedad anterior,sportsData
es la versión pública de solo lectura de esta propiedad. - El bloque de inicializador
init{}
inicializa_currentSport
y_sportsData
. Se inicializa_sportsData
con la lista completa de deportes dedata/SportsData.kt
. Se inicializa_currentSport
con el primer elemento de la lista. - La función
updateCurrentSport()
toma una instancia deSports
y actualiza_currentSport
con el valor que se pasó.
SportsAdapter.kt
Este es el adaptador para RecyclerView
. En el constructor, se pasa el objeto de escucha de clics. La mayor parte del código de este archivo es código estándar que conoces de codelabs anteriores.
SportsListFragment.kt
Este es el fragmento de la primera pantalla, donde se muestra la lista de deportes.
- La función
onCreateView()
aumenta el XML de diseñofragment_sports_list
con el objeto de vinculación. - La función
onViewCreated()
configura el adaptadorRecyclerView
. Actualiza al deporte seleccionado por el usuario como el deporte actual en elViewModel
compartido, elSportsViewModel
. Navega a la pantalla de detalles con las noticias sobre deportes y envía la lista de deportes al adaptador para que se muestre a través desubmitList(List)
.
NewsDetailsFragment.kt
Esta es la segunda pantalla de tu app, en la que se muestra texto del marcador de posición de las noticias sobre deportes.
- La función
onCreateView()
aumenta el XML de diseñofragment_sports_news
con el objeto de vinculación. - La función
onViewCreated()
adjunta un observador en la propiedad deSportsViewModel
,currentSport
, para actualizar la IU automáticamente cuando cambien los datos. Dentro del observador, se actualizan el título, la imagen y las noticias de los deportes.
Compila y ejecuta la app
- Compila y ejecuta la app en un emulador o dispositivo. Selecciona cualquier elemento de la lista de deportes. La app debería navegar a la segunda pantalla con el texto del marcador de posición de las noticias.
4. Patrón de lista-detalles
La app de partida actual no puede aprovechar al máximo el espacio en pantalla en dispositivos más grandes, como las tablets. Para resolver este problema, debes mostrar la IU de la app usando el patrón de lista y detalles, que descubrirás en este codelab.
Cómo ejecutar la app en una tablet
En esta tarea, crearás un emulador con un perfil para tablets. Una vez que se haya creado el emulador, ejecutarás el código de partida de la app de deportes y observarás la IU.
- En Android Studio, ve a Tools > AVD Manager.
- Aparecerá la ventana Android Virtual Device Manager. Haz clic en + Create New Virtual Device... en la parte inferior.
- Aparecerá la ventana Virtual Device Configuration. Aquí configurarás el hardware y el SO del emulador. Haz clic en Tablet en el panel izquierdo. Selecciona Pixel C o cualquier otro perfil de hardware similar en el panel central.
- Haz clic en Next.
- Selecciona la imagen del sistema más reciente. Al momento de escribir este codelab, es R (nivel de API 30).
- Haz clic en Next.
- Si lo deseas, ahora puedes cambiar el nombre del dispositivo virtual.
- Haz clic en Finish.
- Se te dirigirá nuevamente a la ventana Android Virtual Device Manager. Haz clic en el ícono de inicio junto al dispositivo virtual recién creado.
- Se debería iniciar el emulador con el perfil para tablets. Ten paciencia. Este proceso puede tardar unos minutos.
- Cierra la ventana Android Virtual Device Manager.
- Ejecuta la app de deportes en el emulador que creaste recientemente.
Ten en cuenta que, en los dispositivos grandes, la app no utiliza toda la pantalla. El patrón de lista-detalles es más eficientes en una pantalla grande que en una lista. Un patrón de elemento y detalles, también llamado patrón principal y de detalles, muestra una lista de elementos en un lado del diseño, mientras que el detalle se muestra al lado cuando presionas un elemento. Por lo general, estas vistas solo se muestran en pantallas grandes, como las tablets, ya que tienen más espacio para mostrar más contenido.
Las siguientes imágenes son un ejemplo de un patrón de lista-detalles:
Los patrones de lista-detalles anteriores muestran una lista de elementos a la izquierda y los detalles del elemento seleccionado a la derecha.
De la misma manera, si usas el patrón anterior en tu app de deportes, el fragmento de noticias será tu pantalla de detalles.
En este codelab, aprenderás a implementar la IU de lista-detalles con SlidingPaneLayout
.
5. Patrón de SlidingPaneLayout
Es posible que una IU de lista-detalles deba comportarse de manera diferente según el tamaño de la pantalla. En las pantallas grandes, hay espacio suficiente para que los paneles de lista y detalles estén uno al lado del otro. Al hacer clic en un elemento de la lista, se muestran los detalles en el panel de detalles. Sin embargo, las pantallas pequeñas podrían parecer abarrotadas. En lugar de mostrar ambos paneles al mismo tiempo, es mejor mostrar uno a la vez. Inicialmente, el panel de lista ocupa toda la pantalla. Al presionar un elemento, se reemplaza el panel de lista con el panel de detalles de ese elemento, que también ocupa la pantalla.
Aprenderás a usar un SlidingPaneLayout para administrar la lógica a fin de seleccionar la experiencia del usuario adecuada según el tamaño de la pantalla actual.
Observa cómo el panel de detalles se desliza sobre el panel de lista en las pantallas más pequeñas.
A continuación, se muestran imágenes que ilustran cómo aparece el SlidingPaneLayout
en una pantalla más pequeña. Observa cómo el panel de detalles se superpone con el panel de lista cuando se selecciona un elemento de la lista. De esta manera, ambos paneles siempre están presentes.
Por lo tanto, SlidingPaneLayout
admite la visualización de dos paneles uno al lado del otro en dispositivos más grandes, pero se adapta automáticamente para mostrar solo un panel a la vez en dispositivos más pequeños, como teléfonos.
6. Cómo agregar dependencias de bibliotecas
- Abre
build.gradle (Module: Sports.app)
. - En la sección
dependencies
, incluye la siguiente dependencia para usarSlidingPaneLayout
en tu app.
dependencies {
...
implementation "androidx.slidingpanelayout:slidingpanelayout:1.2.0-beta01"
}
7. Cómo configurar un XML de fragmentos de la lista de deportes
En esta tarea, convertirás el diseño raíz de fragment_sports_list
a SlidingPaneLayout
. Como ya aprendiste, SlidingPaneLayout
proporciona un diseño horizontal de dos paneles para usar en el nivel superior de una IU. Este diseño usa el primer panel como una lista de contenido o un navegador, subordinado a una vista principal de detalles para mostrar contenido en el otro panel.
En la app de Deportes, el primer panel será RecyclerView
, que mostrará la lista de deportes, y el segundo, las noticias sobre deportes.
Agrega SlidingPaneLayout
- Abre
fragment_sports_list.xml
. Ten en cuenta que el diseño raíz es un elementoFrameLayout
. - Cambia
FrameLayout
aandroidx.slidingpanelayout.widget.SlidingPaneLayout.
.
<androidx.slidingpanelayout.widget.SlidingPaneLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SportsListFragment">
<androidx.recyclerview.widget.RecyclerView...>
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
- Agrega un atributo
android:id
aSlidingPaneLayout
y asígnale un valor de@+id/sliding_pane_layout
.
<androidx.slidingpanelayout.widget.SlidingPaneLayout
...
android:id="@+id/sliding_pane_layout"
...>
Agrega un segundo panel a SlidingPaneLayout
En esta tarea, agregarás un segundo elemento secundario a SlidingPaneLayout
. Se mostrará como el panel de contenido correcto.
- En
fragment_sports_list.xml
, debajo deRecyclerView
, agrega un segundo elemento secundario,androidx.fragment.app.FragmentContainerView
. - Agrega los atributos obligatorios,
layout_height
ylayout_width
, aFragmentContainerView
. Asígnales un valor dematch_parent
. Ten en cuenta que actualizarás estos valores más tarde.
<androidx.fragment.app.FragmentContainerView
android:layout_height="match_parent"
android:layout_width="match_parent"/>
- Agrega un atributo
android:id
aFragmentContainerView
y asígnale un valor de@+id/detail_container
.
android:id="@+id/detail_container"
- Agrega
NewsDetailsFragment
aFragmentContainerView
con el atributoandroid:name
.
android:name="com.example.android.sports.NewsDetailsFragment"
Actualiza el atributo layout_width
SlidingPaneLayout
usa el ancho de los dos paneles para determinar si se muestran los paneles uno al lado del otro. Por ejemplo, si el panel de la lista se mide para tener un tamaño mínimo de 300dp
y el panel de detalles necesita 400dp
, SlidingPaneLayout
mostrará automáticamente los dos paneles uno al lado del otro, siempre que tenga disponibles al menos 700dp
de ancho.
Las vistas secundarias se superponen si el ancho combinado supera el ancho disponible en el SlidingPaneLayout
. En ese caso, las vistas secundarias se expanden para llenar el ancho disponible en el SlidingPaneLayout
.
Para determinar el ancho de las vistas secundarias, debes contar con información básica sobre el ancho de la pantalla del dispositivo. En la siguiente tabla, se muestra la lista de puntos de interrupción determinados para que diseñes, desarrolles y pruebes con diseños redimensionables. Se eligieron específicamente a los efectos de equilibrar la simplicidad del diseño con la flexibilidad con el propósito de optimizar la app en casos únicos.
Ancho | Punto de interrupción | Representación del dispositivo |
Ancho compacto | Menos de 600 dp | 99.96% de los teléfonos en orientación vertical |
Ancho medio | 600 dp o más | El 93.73% de las tablets en portraitLarge desplegaron pantallas internas en orientación vertical |
Ancho expandido | 840 dp o más | El 97.22% de las tablets en landscapeLarge desplegaron pantallas internas en orientación horizontal. |
En la app de Deportes debes mostrar un solo panel, que es la lista de deportes en teléfonos con un ancho inferior a 600dp
. Para mostrar ambos paneles en tablets, el ancho combinado debe ser mayor que 840dp
. Puedes usar un ancho de 550dp
para el primer elemento secundario, la vista de reciclador, y 300dp
para el segundo elemento secundario, FragmentContainerView
.
- En
fragment_sports_list.xml
, cambia el ancho del diseño deRecyclerView
a550dp
y el deFragmentContainerView
a300dp
.
<androidx.recyclerview.widget.RecyclerView
...
android:layout_width="550dp"
.../>
<androidx.fragment.app.FragmentContainerView
...
android:layout_width="300dp"
.../>
- Ejecuta la app en el emulador con el perfil de tablet y en el emulador con el perfil de teléfono.
Observa que se muestran dos paneles en la tablet. En el próximo paso, corregirás el ancho del segundo panel de la tablet.
- Ejecuta la app en el emulador con el perfil de teléfono.
Agrega layout_weight
En esta tarea, corregirás la IU en la tablet y harás que el segundo panel ocupe todo el espacio restante.
SlidingPaneLayout
admite la definición de cómo se divide el espacio restante después de la medición a través del parámetro de diseño layout_weight
en las vistas secundarias si las vistas no se superponen. Este parámetro se aplica solo al ancho.
- En
fragment_sports_list.xml
, agregalayout_weight
aFragmentContainerView
y asígnale un valor de1
. Ahora, el segundo panel se expande para llenar el espacio restante después de que se mide el panel de lista.
android:layout_weight="1"
- Ejecuta la app.
¡Felicitaciones! Agregaste SlidingPaneLayout
correctamente. Aún no has terminado. Deberás implementar la navegación hacia atrás y actualizar el segundo panel cuando se seleccione un elemento de la lista. Implementarás esto en una tarea posterior.
8. Cómo intercambiar el panel de detalles
Ejecuta la app en el emulador con el perfil de tablet. Selecciona un elemento de la lista de deportes. Observa que la app navega al panel de detalles.
En esta tarea, corregirás este problema. Actualmente, el contenido del panel dual se está actualizando con el deporte seleccionado y, luego, la app navega a NewsDetailsFragment
.
- En el archivo
SportsListFragment
, en la funciónonViewCreated()
, ubica las siguientes líneas, que navegan a la pantalla de detalles.
// Navigate to the details screen
val action = SportsListFragmentDirections.actionSportsListFragmentToNewsFragment()
this.findNavController().navigate(action)
- Reemplaza las líneas anteriores con el siguiente código:
binding.slidingPaneLayout.openPane()
Llama a openPane()
en SlidingPaneLayout
para cambiar el segundo panel sobre el primero. Esta opción no tendrá ningún efecto visible si los dos paneles están visibles, como en una tablet.
- Ejecuta la app en el emulador de tablets y teléfonos. Observa que el contenido del panel dual se actualiza correctamente.
En tu próxima tarea, la siguiente funcionalidad que agregarás a la app es la navegación hacia atrás personalizada.
9. Cómo agregar la navegación hacia atrás personalizada
En dispositivos más pequeños, en los que los paneles de lista y detalles se superponen, debes asegurarte de que el botón Atrás del sistema lleve al usuario del panel de detalles al panel de listas. Para ello, proporciona navegación hacia atrás personalizada y conecta un OnBackPressedCallback
al estado actual de SlidingPaneLayout
.
Navegación hacia atrás
La navegación hacia atrás hace referencia a cómo los usuarios navegan de manera inversa por el historial de pantallas que visitaron anteriormente. Todos los dispositivos Android incluyen un botón Atrás para este tipo de navegación. Según el dispositivo Android del usuario, este botón puede ser un botón físico o de software.
Navegación hacia atrás personalizada
Android mantiene una pila de actividades de destinos a medida que el usuario navega por tu aplicación. Por lo general, esto permite que Android navegue correctamente a destinos anteriores cuando se presiona el botón Atrás. Sin embargo, hay algunos casos en los que tu app podría necesitar implementar su propio comportamiento del botón Atrás a fin de brindar una mejor experiencia del usuario.
Por ejemplo, cuando usas una WebView, como un navegador Chrome, es posible que quieras anular el comportamiento predeterminado del botón Atrás para permitir que el usuario navegue hacia atrás en su historial de navegación en lugar de las pantallas anteriores en tu app.
Del mismo modo, debes proporcionar una navegación hacia atrás personalizada a SlidingPaneLayout
y navegar por la app desde el panel de detalles hasta el panel de lista.
Implementa la navegación hacia atrás personalizada
Para implementar la navegación hacia atrás personalizada en tu app de Deportes, debes hacer lo siguiente:
- Define una devolución de llamada personalizada para controlar la pulsación de la tecla Atrás, que anula
OnBackPressedCallback
. - Registra y agrega la instancia de devolución de llamada.
Primero, define la devolución de llamada personalizada.
- En el archivo
SportsListFragment
, agrega una clase nueva debajo de la definición de la claseSportsListFragment
. Asígnale el nombreSportsListOnBackPressedCallback
. - Pasa una instancia
private
deSlidingPaneLayout
como parámetro del constructor.
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
)
- Extiende la clase desde
OnBackPressedCallback
. La claseOnBackPressedCallback
controla las devoluciones de llamada deonBackPressed
. Pronto corregirás el error de parámetro del constructor.
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback()
El constructor de OnBackPressedCallback
toma un valor booleano para el estado habilitado inicial. Solo cuando se habilita una devolución de llamada (es decir, cuando el objeto isEnabled()
muestra verdadero) el despachador llama al handleOnBackPressed()
de la devolución de llamada para controlar el evento del botón Atrás.
- Pasa
slidingPaneLayout.
isSlideable
*&& slidingPaneLayout.isOpen
* como parámetro del constructor aOnBackPressedCallback
. El valor booleanoisSlideable
solo será verdadero si el segundo panel es deslizable, lo que sucedería en una pantalla más pequeña, y se muestra un solo panel. El valor deisOpen
serátrue
si el segundo panel (el panel de contenido) está completamente abierto.
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen)
Este código garantizará que la devolución de llamada solo esté habilitada en los dispositivos con pantallas más pequeñas y cuando el panel de contenido esté abierto.
- Para corregir el error sobre el método no implementado, haz clic en la bombilla roja y selecciona Implement members.
- En la ventana emergente Implement members, haz clic en OK para anular el método
handleOnBackPressed
.
Tu clase debería verse así:
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen) {
/**
* Callback for handling the [OnBackPressedDispatcher.onBackPressed] event.
*/
override fun handleOnBackPressed() {
TODO("Not yet implemented")
}
}
- Dentro de la función
handleOnBackPressed()
, borra la declaración TODO y agrega el siguiente código para cerrar el panel de contenido y volver al panel de lista.
slidingPaneLayout.closePane()
Supervisa eventos de SlidingPaneLayout
Además de controlar los eventos de presionar la tecla Atrás, debes escuchar y supervisar los eventos relacionados con el panel deslizante. A medida que se desliza el panel de contenido, se debe habilitar o inhabilitar la devolución de llamada según corresponda. Para ello, usarás PanelSlideListener
.
La interfaz SlidingPaneLayout.PanelSlideListener
contiene tres métodos abstractos onPanelSlide()
, onPanelOpened()
y onPanelClosed()
. Se llama a estos métodos cuando el panel de detalles se desliza, se abre y se cierra.
- Extiende la clase
SportsListOnBackPressedCallback
desdeSlidingPaneLayout.PanelSlideListener
. - Para resolver el error, implementa los tres métodos. Haz clic en la bombilla roja y selecciona Implement members en Android Studio.
- Tu clase
SportsListOnBackPressedCallback
debería ser similar a la siguiente:
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen),
SlidingPaneLayout.PanelSlideListener{
override fun handleOnBackPressed() {
slidingPaneLayout.closePane()
}
override fun onPanelSlide(panel: View, slideOffset: Float) {
TODO("Not yet implemented")
}
override fun onPanelOpened(panel: View) {
TODO("Not yet implemented")
}
override fun onPanelClosed(panel: View) {
TODO("Not yet implemented")
}
}
- Quita las sentencias TODO.
- Habilita la devolución de llamada
OnBackPressedCallback
, cuando se abra el panel de detalles (es visible). Para ello, se debe realizar una llamada a la funciónsetEnabled()
y pasartrue
. Escribe el siguiente código dentro deonPanelOpened()
:
setEnabled(true)
- El código anterior se puede simplificar mediante la sintaxis de acceso a la propiedad.
override fun onPanelOpened(panel: View) {
isEnabled = true
}
- De manera similar, establece
isEnabled
enfalse
cuando el panel de detalles esté cerrado.
override fun onPanelClosed(panel: View) {
isEnabled = false
}
- El último paso para completar la devolución de llamada consiste en agregar la clase de objeto de escucha
SportsListOnBackPressedCallback
a la lista de objetos de escucha que recibirán notificaciones sobre los eventos de deslizamiento del panel de detalles. Agrega un bloqueinit
a la claseSportsListOnBackPressedCallback
. Dentro del bloqueinit
, realiza una llamada aslidingPaneLayout.addPanelSlideListener()
y pasathis
.
init {
slidingPaneLayout.addPanelSlideListener(this)
}
La clase SportsListOnBackPressedCallback
completada debería ser similar a la siguiente:
class SportsListOnBackPressedCallback(
private val slidingPaneLayout: SlidingPaneLayout
): OnBackPressedCallback(slidingPaneLayout.isSlideable && slidingPaneLayout.isOpen),
SlidingPaneLayout.PanelSlideListener{
init {
slidingPaneLayout.addPanelSlideListener(this)
}
override fun handleOnBackPressed() {
slidingPaneLayout.closePane()
}
override fun onPanelSlide(panel: View, slideOffset: Float) {
}
override fun onPanelOpened(panel: View) {
isEnabled = true
}
override fun onPanelClosed(panel: View) {
isEnabled = false
}
}
Registra la devolución de llamada
Para ver la devolución de llamada en acción, regístrala con el despachador OnBackPressedDispatcher
.
La clase básica de FragmentActivity
te permite controlar el comportamiento del botón Atrás con su OnBackPressedDispatcher
. El elemento OnBackPressedDispatcher
controla cómo se despachan los eventos del botón Atrás a uno o más objetos OnBackPressedCallback
.
Agrega la devolución de llamada con el método addCallback()
. Este método toma un objeto LifecycleOwner
. De esta manera, se garantiza que el OnBackPressedCallback
solo se agregue cuando el objeto LifecycleOwner
sea Lifecycle.State.STARTED
. La actividad o el fragmento también quita las devoluciones de llamada registradas cuando se destruye su objeto LifecycleOwner
asociado, lo que evita fugas de memoria y permite que se lo utilice en fragmentos y otros propietarios del ciclo de vida con tiempos de vida más cortos.
El método addCallback()
también agrega en la instancia la clase de devolución de llamada como segundo parámetro. Deberás registrar la devolución de llamada con los siguientes pasos:
- En el archivo
SportsListFragment
, dentro de la funciónonViewCreated()
, justo debajo de la declaración de la variable de vinculación, crea una instancia paraSlidingPaneLayout
y asígnale el valor debinding.slidingPaneLayout
.
val slidingPaneLayout = binding.slidingPaneLayout
- En el archivo
SportsListFragment
, dentro de la funciónonViewCreated()
, debajo de la declaración deslidingPaneLayout
, agrega el siguiente código:
// Connect the SlidingPaneLayout to the system back button.
requireActivity().onBackPressedDispatcher.addCallback(
viewLifecycleOwner,
SportsListOnBackPressedCallback(slidingPaneLayout)
)
El código anterior usa addCallback()
y pasa viewLifecycleOwner
y una instancia de SportsListOnBackPressedCallback
. Esta devolución de llamada solo está activa durante el ciclo de vida del fragmento.
- Llegó la hora de ejecutar la app en un emulador con un perfil de teléfono y ver la funcionalidad personalizada del botón Atrás en acción.
10. Modo bloqueado
Cuando se superponen los paneles de lista y de detalles en pantallas de menor tamaño, como los teléfonos, los usuarios pueden deslizar el dedo en ambas direcciones de forma predeterminada para alternar libremente entre los dos paneles, incluso cuando no usan la navegación por gestos. Para bloquear o desbloquear el panel de detalles, configura el modo bloqueado de SlidingPaneLayout
.
- En el emulador con el perfil de teléfono, intenta deslizar el panel de detalles para quitarlo de la pantalla.
- También puedes deslizar el panel de detalles para que aparezca en la pantalla. Inténtalo tú mismo.
- Esta no es una función deseada en tu app de Deportes. Se recomienda bloquear el elemento
SlidingPaneLayout
para evitar que los usuarios deslicen el panel dentro y fuera de la pantalla con gestos. Para bloquear el elemento, en el métodoonViewCreated()
, debajo de la definición deslidingPaneLayout
, establecelockMode
enLOCK_MODE_LOCKED
:
slidingPaneLayout.lockMode = SlidingPaneLayout.LOCK_MODE_LOCKED
Si deseas obtener más información sobre los otros modos bloqueados, consulta la documentación.
- Ejecuta la app una vez más y observa que el panel de detalles ahora está bloqueado.
Felicitaciones por agregar SlidingPaneLayout
a tu app.
11. Código de solución
El código de la solución de este codelab se encuentra en el proyecto y módulo que se muestran a continuación.
- Navega a la página de repositorio de GitHub del proyecto.
- Verifica que el nombre de la rama coincida con el especificado en el codelab. Por ejemplo, en la siguiente captura de pantalla, el nombre de la rama es main.
- En la página de GitHub de este proyecto, haz clic en el botón Code, el cual abre una ventana emergente.
- En la ventana emergente, haz clic en el botón Download ZIP para guardar el proyecto en tu computadora. Espera a que se complete la descarga.
- Ubica el archivo en tu computadora (probablemente en la carpeta Descargas).
- Haz doble clic en el archivo ZIP para descomprimirlo. Se creará una carpeta nueva con los archivos del proyecto.
Abre el proyecto en Android Studio
- Inicia Android Studio.
- En la ventana Welcome to Android Studio, haz clic en Open.
Nota: Si Android Studio ya está abierto, selecciona la opción de menú File > Open.
- En el navegador de archivos, ve hasta donde se encuentra la carpeta del proyecto descomprimida (probablemente en Descargas).
- Haz doble clic en la carpeta del proyecto.
- Espera a que Android Studio abra el proyecto.
- Haz clic en el botón Run para compilar y ejecutar la app. Asegúrate de que funcione como se espera.