Window Manager de Jetpack para dispositivos plegables

Window Manager de Jetpack proporciona una API estándar para trabajar con todos los dispositivos plegables. Contiene dos clases importantes:

  • DisplayFeature: Identifica las interrupciones en la superficie de la pantalla plana continua, como las bisagras o los pliegues. El Administrador de ventanas devolverá una colección de características de presentación de una devolución de llamada de cambio de diseño.
  • FoldingFeature: proporciona información sobre una característica específica del dispositivo. Si bien Surface Duo solo tiene una característica de plegado, es posible que otros dispositivos tengan más.

Una guía similar está en Android Foldable Codelab. Obtenga más información sobre el desarrollo de dispositivos plegables en la documentación de Android. Los ejemplos del equipo de Android también están disponibles en GitHub. Las notas de la versión de Jetpack registran los cambios en el Administrador de ventanas en cuanto se actualiza.

Sugerencia

Los controles y las clases auxiliares de la biblioteca de doble pantalla Surface Duo funcionan con Window Manager. Siga las instrucciones para agregar los paquetes correctos al proyecto de su aplicación.

Para usar Window Manager directamente en el código, siga las instrucciones que tiene a continuación:

Adición de dependencias

  1. Asegúrese de que tiene el repositorio mavenCentral() en el archivo build.gradle de nivel superior:

    allprojects {
        repositories {
            google()
            mavenCentral()
         }
    }
    
  2. Asegúrese de que compileSdkVersion y targetSdkVersion estén establecidos en API 31 o posterior en el archivo build.gradle a nivel del módulo:

    android { 
        compileSdkVersion 31
    
        defaultConfig { 
            targetSdkVersion 31
        } 
        ... 
    }
    
    
  3. Agregue las siguientes dependencias al archivo build.gradle de nivel de módulo:

    dependencies {
        implementation "androidx.window:window:1.0.0"
        implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
    }
    

Uso de Window Manager en el código de Kotlin

Al acceder a las propiedades de Window Manager en los proyectos de Kotlin, es importante configurar el flujo correcto de información. De lo contrario, puede recibir demasiadas actualizaciones de eventos (o muy pocas), y el rendimiento de la aplicación podría verse afectado.

Para inicializar el proceso y usar un objeto WindowInfoTracker, siga estos pasos:

  1. En la clase MainActivity, cree una variable para WindowInfoTracker. Asegúrese de que import androidx.window.layout.WindowInfoTracker se agregue al principio del archivo.

    class MainActivity : AppCompatActivity() {
        private lateinit var windowInfoTracker: WindowInfoTracker
    
  2. Inicialice WindowInfoTracker en el método onCreate de la actividad y configure un flujo para recopilar información de la propiedad windowLayoutInfo.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        // Initialize the window manager
        windowInfoTracker = WindowInfoTracker.getOrCreate(this@MainActivity)
    
        // Set up a flow
        lifecycleScope.launch(Dispatchers.Main) {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                windowInfoTracker.windowLayoutInfo(this@MainActivity)
                    .collect { 
                        // Check FoldingFeature properties here
                    }
            }
        }
    }
    

    Asegúrese de que estas importaciones también se agreguen al principio del archivo:

    import androidx.lifecycle.Lifecycle
    import androidx.lifecycle.lifecycleScope
    import androidx.lifecycle.repeatOnLifecycle
    import kotlinx.coroutines.Dispatchers
    import kotlinx.coroutines.flow.collect
    import kotlinx.coroutines.launch
    
  3. Agregue código para comprobar el flujo WindowLayoutInfo de las propiedades de la característica de plegado. Cuando se ejecute este código, la actividad se actualizará con las características actuales de posición y visualización del dispositivo (si abarcan el pliegue o la bisagra).

    En el fragmento de código siguiente, la actividad mostrará un texto diferente en función de las propiedades de FoldingFeature.

    En este ejemplo hay un elemento TextView denominado layout_change_text que muestra el tipo de oclusión y el valor isSeparating de cualquier función de plegado detectada.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        windowInfoTracker = WindowInfoTracker.getOrCreate(this@MainActivity)
    
        lifecycleScope.launch(Dispatchers.Main) {
            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
                windowInfoTracker.windowLayoutInfo(this@MainActivity)
                    .collect { newLayoutInfo ->
                        layout_change_text.text = "No display features detected"
                        for (displayFeature : DisplayFeature in newLayoutInfo.displayFeatures) {
                            if (displayFeature is FoldingFeature && displayFeature.occlusionType == FoldingFeature.OcclusionType.NONE) {
                                layout_change_text.text = "App is spanned across a fold, " +
                                    "isSeparating = ${displayFeature.isSeparating}"
                            }
                            if (displayFeature is FoldingFeature && displayFeature.occlusionType == FoldingFeature.OcclusionType.FULL) {
                                layout_change_text.text = "App is spanned across a hinge, " +
                                    "isSeparating = ${displayFeature.isSeparating}"
                            }
                        }
                    }
            }
        }
    }
    

Propiedades de características de plegado

La clase WindowLayoutInfo tiene una colección de DisplayFeature elementos, uno o más de los cuales podrían ser instancias de la clase FoldingFeature.

Las características de plegado tienen las siguientes propiedades:

  • bounds: coordenadas del rectángulo delimitador de una característica de plegado
  • occlusionType: si una característica de plegado oculta el contenido (FULL o NONE)
  • orientation: orientación de una característica de plegado (HORIZONTAL o VERTICAL)
  • state: ángulo de una característica de plegado (HALF_OPENED o FLAT)
  • isSeparating: si una característica de plegado separa el área de presentación en dos secciones distintas

Puede consultar estas propiedades para tomar decisiones sobre cómo ajustar el diseño después de realizar los cambios de configuración.

isSeparating

Al decidir dónde colocar controles o cuántos paneles de contenido se van a mostrar, use la propiedad isSeparating. Con este campo podrá asegurarse de que la aplicación proporcione la mejor experiencia de usuario en todos los dispositivos plegables:

  • En el caso de los dispositivos de doble pantalla, el valor siempre será "true" cuando una aplicación se expanda a través de la bisagra.
  • En el caso de otros dispositivos plegables, el valor solo será "true" cuando el estado sea HALF_OPENED, como cuando un dispositivo está en posición horizontal.

Use la propiedad isSeparating para decidir si debe adaptar el diseño de la interfaz de usuario de la aplicación para un dispositivo plegable o si tiene que usar la interfaz de usuario predeterminada cuando no haya separación:

private fun updateCurrentLayout(newLayoutInfo: WindowLayoutInfo) {
   for (displayFeature in newLayoutInfo.displayFeatures) {
       val foldFeature = displayFeature as? FoldingFeature
       foldFeature?.let {
           if (it.isSeparating) {
               // The content is separated by the FoldingFeature.
               // Here is where you should adapt your UI.
           } else {
               // The content is not separated.
               // Users can see and interact with your UI properly.
           }
       }
   }
}

Para ver un ejemplo más elaborado de cómo usar este campo, consulte el ejemplo isSeparating.

Google también proporciona documentación y ejemplos relacionados con esta propiedad como parte de su guía para dispositivos plegables y de pantalla grande.

Ejemplos

El repositorio surface-duo-jetpack-window-manager-samples de GitHub contiene una serie de ejemplos de Kotlin que muestran diferentes patrones de experiencia del usuario en una pantalla doble, compilados mediante Window Manager de Jetpack y el sistema de vistas tradicional.

El repositorio surface-duo-compose-samples de GitHub también contiene ejemplos de Kotlin para dispositivos de pantalla doble que usan Window Manager de Jetpack, pero en estos ejemplos, la interfaz de usuario se compila con Jetpack Compose.

API de Java

Consulte la entrada de blog sobre el Administrador de ventanas de Jetpack con Java y este ejemplo de Java para ver cómo acceder a la clase WindowInfoTracker a través de WindowInfoTrackerCallbackAdapter.

Recursos