Desde que Samsung lanzó el primer Galaxy Z Fold (sin contar a Royole) en 2019, los fabricantes de Android han seguido sus soluciones plegables una tras otra. Después de eso, el mercado de teléfonos móviles con pantalla plegable ha mantenido un rápido crecimiento. Por ejemplo, en la primera mitad de En 2023, el volumen total de ventas fue de 2,27 millones de unidades, un aumento interanual del 102,0%.
Aunque en comparación con los envíos totales de teléfonos móviles de 130 millones de unidades en la primera mitad del año, solo puede considerarse como una fracción, pero es innegable que la probabilidad de que los desarrolladores de aplicaciones encuentren teléfonos móviles plegables no es baja, especialmente estos Es probable que los usuarios sean usuarios de “alto valor”.
Entonces, a partir de 2023, la adaptación de la pantalla plegable se convertirá gradualmente en uno de los KPI principales de Android, entonces, ¿qué sucede si no coincide? Si se adapta, ¿por qué medios ? Este artículo le permitirá comprender en profundidad este tema.
⚠️Este artículo es muy largo y se puede guardar para emergencias.
Modo buzón
En primer lugar, si no es adecuado, lo más probable ( no necesariamente ) es que su aplicación se muestre en modo Letterboxing y es posible que vea que la aplicación existe como se muestra en la siguiente figura, es decir, cuando la relación de aspecto de la aplicación y la pantalla La aplicación puede abrirse en modo Letterbox cuando la báscula no es compatible .
Generalmente, la aplicación bloquea la dirección de rotación y adopta el tamaño no redimensionable.
Por supuesto, ingresar al modo Letterboxing está relacionado con la versión de TargetSDK, la configuración de la aplicación y la resolución de la pantalla , y la presentación del modo Letterboxing en diferentes versiones del sistema operativo también puede ser diferente, por ejemplo:
-
Android 12 (API 31) comenzó a introducir mejoras en Letterboxing, que pueden ser configuradas y soportadas por los fabricantes de teléfonos móviles:
- Esquinas redondeadas: Windows admite esquinas redondeadas
- Transparencia de la barra del sistema: la barra de estado y la barra de navegación que cubren la aplicación admiten la translucidez
- Relación de aspecto configurable: la relación de aspecto de la aplicación se puede ajustar para mejorar la apariencia de la aplicación.
-
12L (API 32) añadido:
- Posición configurable: en pantallas grandes, los fabricantes de dispositivos pueden colocar aplicaciones en el lado izquierdo o derecho de la pantalla.
- Botón de reinicio: los fabricantes de dispositivos pueden darle una nueva apariencia al botón de reinicio en el modo de compatibilidad de tamaño. (El modo de compatibilidad de tamaño puede hacer que el ancho o alto de la aplicación llene la pantalla tanto como sea posible)
Cuando el sistema determina que la visualización de Letterboxing se puede mejorar reescalando la aplicación para llenar la ventana de visualización, Android pondrá la aplicación en modo de compatibilidad de tamaño, en este momento el sistema mostrará un control de reinicio y recreará el proceso de la aplicación. recrear la actividad y volver a dibujarla después de la confirmación Adaptar.
-
Android 13 (API 33) agrega un cuadro de diálogo de aviso guiado por el usuario:
Entonces, ¿cuándo entras en modo buzón? Generalmente, puede entenderse simplemente como:
android:resizeableActivity=false
Cuando la relación de aspecto declarada por la aplicación a continuación no es compatible con el contenedor (por ejemplo, el ancho de la pantalla excedeandroid:maxAspectRatio
).setIgnoreOrientationRequest(true)
Después de reducir la configuración del sistema para ignorar la orientación de la pantalla, abra la interfaz vertical forzada en orientación horizontal.
El punto central aquí es en realidad que resizeableActivity
se utiliza para declarar si el sistema puede ajustar el tamaño de la aplicación para adaptarse a pantallas de diferentes tamaños. De hecho, estrictamente hablando resizeableActivity
, no necesariamente hace que la aplicación entre en el modo Letterboxing . También está relacionado con la versión API:
- La configuración del modo de pantalla dividida se introdujo en Android 7.0 (API 24)
resizeableActivity
. - En Android 11 (API 30) y versiones inferiores se utiliza para configurar si la App soporta el modo multiventana, si es false no lo soporta y entra en modo Letterboxing.
- En Android 12 (API 31) y versiones superiores, sin importar
resizeableActivity
lo que esté configurado, la aplicación admitirá el modo de ventanas múltiples en pantallas grandes (sw >= 600 dp), por lo que solo se usa para especificar si la aplicación admite pantallas pequeñas (sw < 600dp) modo de ventanas múltiples.
sw >= 600dp
Se puede entender simplemente que el ancho absoluto de su pantalla es superior a 600 ppp.
Entonces algunas personas dijeron, ¿ y si lo uso en Android 12 android:resizeableActivity=false
y no encaja nada? Solo puedo decir: "Existe una cierta probabilidad" de que se bloquee directamente como se muestra en la siguiente figura .
¿Eso significa que si no uso una versión superior de TargetSDK, no necesito trabajar en él?
Activity
No del todo, al menos necesitas realizar alguna configuración simple en tu aplicación o , porque ya en Android 7.0 (API 24), resizeableActivity
el valor predeterminado de se cambia a verdadero .
Entonces, si no desea adaptarse a la interfaz de usuario del modo de pantalla grande, pero desea ingresar al modo Letterboxing, aún debe configurarlo manualmente en AndroidManifest application
o en la configuración correspondiente .Activity
android:resizeableActivity="false"
Además, el modo de visualización del modo Letterboxing maxAspectRatio
también está relacionado con. Cuando la relación de pantalla excede, maxAspectRatio
se llenará con bordes negros. Generalmente, la recomendación oficial es establecer maxAspectRatio en 2.4 (12: 5), y el método de configuración es también relacionado con el nivel API:
-
Android 8.0 y superior se pueden
android:maxAspectRatio
configurar mediante<activity android:name=".MainActivity" android:maxAspectRatio="2.4" />
-
Android 8.0 y versiones anteriores se pueden
meta-data android.max_aspect
configurar mediante<meta-data android:name="android.max_aspect" android:value="2.4" />
PD: Si
resizeableActivity
es cierto,maxAspectRatio
no tendrá efecto.
Como se muestra en la imagen, el botón de reinicio de Android 12L (API 32) mencionado anteriormente puede hacer que el final de la aplicación se adapte a la pantalla tanto como sea posible y reduzca el borde negro.
Otro punto es que cuando la pantalla plegable se despliega y se cierra, el sistema puede destruir y recrear toda la pantalla cuando la pantalla cambia Activity
, por lo que debemos configurar android:configChanges
para evitar el reinicio :
android:configChanges="screenLayout|smallestScreenSize|screenSize"
Finalmentesupports_size_changes
, cabe señalar que si no desea admitir el modo de ventanas múltiples, pero es posible que se vea obligado a ingresar al modo de ventanas múltiples debido al sistema y luego no desea que se reinicie cada vez, puede configurar supports_size_changes
para garantizar la continuidad de la operación.
<meta-data
android:name="android.supports_size_changes" android:value="true" />
Así que aquí hay un breve resumen:
-
Cuando la relación de aspecto de la aplicación no es compatible con la relación de pantalla, la aplicación ingresará al modo Letterboxing cuando la dirección de rotación y el tamaño estén bloqueados.
-
resizeableActivity
El efecto depende principalmente de la versión de TargetSDK, Android 12 (API 31) y versiones superiores aún pueden ingresar al modo de pantalla dividida. -
maxAspectRatio
El papel depende principalmente deresizeableActivity
-
Configurar
android:configChanges
ysupports_size_changes
evitar reiniciosActivity
para garantizar la continuidad
Soporte oficial de adaptación
El siguiente paso es presentar el esquema de adaptación. Primero, veamos esta imagen. De hecho, el funcionario ha definido sugerencias de uso para nosotros de acuerdo con los escenarios de uso. La información clave es:
- Componer
- Incrustación de actividad
- Diseño del panel deslizante
Además, la especificación del nivel de tamaño de la ventana se establece en la coincidencia oficial del tamaño de la pantalla, por ejemplo:
- Compacto : dispositivos móviles comunes, ancho < 600 dp
- Mediano : Pantalla vertical para pantalla plegable o tableta, 600 dp < ancho < 840 dp
- Expandido : Pantalla expandida, tableta o tablet, etc., ancho > 840dp
Por supuesto, hay juicios basados en la altura, pero la mayoría de las aplicaciones pueden crear una interfaz de usuario receptiva considerando solo la categoría de tamaño de ventana de ancho .
Componer
De hecho, Compose no necesita decir mucho. El diseño responsivo en sí mismo tiene ventajas inherentes al adaptarse a pantallas plegables. Con los parámetros de pantalla actuales proporcionados por Jetpack WindowManager API, puede lograr de manera flexible diferentes efectos de interfaz de usuario.
Por ejemplo, Compose puede usar material3-window-size-class
la biblioteca y luego usarla para calculateWindowSizeClass()
calcular la ventana actualWindowSizeClass
, cambiando así el diseño de la interfaz de usuario:
import androidx.activity.compose.setContent
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
class MyActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// Calculate the window size class for the activity's current window. If the window
// size changes, for example when the device is rotated, the value returned by
// calculateSizeClass will also change.
val windowSizeClass = calculateWindowSizeClass(this)
// Perform logic on the window size class to decide whether to use a nav rail.
val useNavRail = windowSizeClass.widthSizeClass > WindowWidthSizeClass.Compact
// MyScreen knows nothing about window size classes, and performs logic based on a
// Boolean flag.
MyScreen(useNavRail = useNavRail)
}
}
}
También se puede adaptar a través decom.google.accompanist:accompanist-adaptive
TwoPane .
TwoPane
Se proporcionan dos ranuras fijas, y la posición predeterminada de las dos ranuras es TwoPaneStrategy
determinada por , que puede decidir organizar las dos ranuras horizontal o verticalmente y configurar el intervalo entre ellas.
Puede encontrar más información en: https://github.com/google/accompanist/tree/3810fe1182cf52c6660787ae3226dfb7f5ad372a/sample/src/main/java/com/google/accompanist/sample/adaptive
Compose también puede usar FlowLayout para adaptarse a los cambios de plegado en diferentes escenarios . FlowLayout contiene FlowRow
y FlowColumn
. Cuando una fila (o columna) no puede caber en el contenido, se ajustará automáticamente. Esto también es muy útil en los escenarios de expansión y contracción de la pantalla plegable. .
También puedes consultar la Demo de Compose adaptándose a la pantalla plegable: https://github.com/android/compose-samples/tree/main/JetNews
Incrustación de actividad
Activity Embedding optimiza el soporte para pantallas grandes al dividir ventanas entre dos actividades o dos instancias de la misma actividad.
En teoría, la incrustación de actividades no requiere refactorización de código; puede determinar cómo la aplicación muestra su actividad (una al lado de la otra o apilada) creando un archivo de configuración XML o realizando una llamada a la API Jetpack WindowManager .
La incrustación de actividades mantiene automáticamente el soporte para pantallas pequeñas de forma predeterminada. Cuando la aplicación está en un dispositivo de pantalla pequeña, las actividades se apilarán una encima de la otra; en una pantalla grande, las actividades se mostrarán una al lado de la otra.
Sobre esta base, puede adaptarse a los cambios en la orientación del dispositivo y funcionar sin problemas en dispositivos plegables, apilando actividades que se desmontan cuando el dispositivo se pliega o despliega, como dividir y apilar en la lista de chat y las páginas de detalles del chat.
Ya sea que se trate de un dispositivo de pantalla grande superior a Android 12L (API 32) o una versión anterior de la plataforma de pantalla plegable, Jetpack WindowManager puede ayudar a crear un diseño de múltiples paneles de incrustación de actividades, que se basa en múltiples actividades en lugar de fragmentos o diseños basados en vistas. (como
SlidingPaneLayout
) son la forma más sencilla de proporcionar una experiencia de usuario en pantalla grande sin refactorizar el código fuente .
Un ejemplo común es la pantalla dividida de lista y detalles. Para garantizar una representación de alta calidad, el sistema inicia primero la actividad de lista y luego la aplicación inicia la actividad de detalle inmediatamente. El sistema de transición espera hasta que ambas actividades se dibujen antes de mostrarlas juntas. Para el usuario, estas dos actividades se inician como una sola página.
Actualmente, la incrustación de actividades es compatible con la mayoría de los dispositivos de pantalla grande que ejecutan Android 12L (API 32) y versiones posteriores.
Usar Jetpack WindowManager para administrar y configurar la incrustación de actividades es bastante flexible . Las reglas XML se pueden preconfigurar o administrar y configurar directamente a través de la API. Para las reglas definidas en el archivo de configuración XML, establezca las siguientes propiedades:
splitRatio
: establece la escala del contenedor. El valor es un número de coma flotante en el rango abierto (0,0, 1,0).splitLayoutDirection
: Especifica cómo se distribuyen los contenedores divididos entre sí. Los valores incluyen:ltr
: de izquierda a derechartl
: De derecha a izquierdalocale
:ltr
ortl
según lo determine la configuración local
Puede ver que Jetpack WindowManager tiene un soporte de configuración muy rico y flexible. En lugar de simplemente dividir la actividad en partes iguales, incluso puede configurar un marcador de posición en blanco para mostrar el marcador de posición.
Para utilizar la incrustación de actividades, debe depender de implementation 'androidx.window:window:xxx'
, luego agregue esta android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED
propiedad al archivo de manifiesto de la aplicación <application>
y establezca el valor en verdadero.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<property
android:name="android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED"
android:value="true" />
</application>
</manifest>
Luego puede crear varias reglas de división a través de xml o API de WindowManager para crear reglas de división y llamarlas.
<!-- main_split_config.xml -->
<resources
xmlns:window="http://schemas.android.com/apk/res-auto">
<!-- Define a split for the named activities. -->
<SplitPairRule
window:splitRatio="0.33"
window:splitLayoutDirection="locale"
window:splitMinWidthDp="840"
window:splitMaxAspectRatioInPortrait="alwaysAllow"
window:finishPrimaryWithSecondary="never"
window:finishSecondaryWithPrimary="always"
window:clearTop="false">
<SplitPairFilter
window:primaryActivityName=".ListActivity"
window:secondaryActivityName=".DetailActivity"/>
</SplitPairRule>
<!-- Specify a placeholder for the secondary container when content is
not available. -->
<SplitPlaceholderRule
window:placeholderActivityName=".PlaceholderActivity"
window:splitRatio="0.33"
window:splitLayoutDirection="locale"
window:splitMinWidthDp="840"
window:splitMaxAspectRatioInPortrait="alwaysAllow"
window:stickyPlaceholder="false">
<ActivityFilter
window:activityName=".ListActivity"/>
</SplitPlaceholderRule>
<!-- Define activities that should never be part of a split. Note: Takes
precedence over other split rules for the activity named in the
rule. -->
<ActivityRule
window:alwaysExpand="true">
<ActivityFilter
window:activityName=".ExpandedActivity"/>
</ActivityRule>
</resources>
Se puede ver más en: https://developer.android.com/guide/topics/large-screens/activity-embedding
Diseño del panel deslizante
SlidingPaneLayout
Admite la visualización de dos paneles uno al lado del otro en dispositivos de pantalla grande y los ajusta automáticamente, mientras que en dispositivos de pantalla pequeña como teléfonos móviles solo se muestra un panel, por lo que también es muy práctico en escenarios plegables.
SlidingPaneLayout
La visualización de los paneles uno al lado del otro está determinada por el ancho de los dos paneles, por ejemplo:
- Si mide y descubre que el panel de lista tiene un tamaño mínimo de 200 dp y el panel de detalles requiere 400 dp, los
SlidingPaneLayout
dos paneles se mostrarán automáticamente uno al lado del otro siempre que el ancho disponible no sea inferior a 600 dp. - Si el ancho total de las subvistas excede
SlidingPaneLayout
el ancho disponible en el archivo, las vistas se superpondrán.
Si las vistas no se superponen,
SlidingPaneLayout
se admiten parámetros de diseñolayout_weight
para que las subvistas especifiquen cómo dividir el espacio restante una vez completada la medición.
Por ejemplo, en este ejemplo SlidingPaneLayout
, el diseño usa RecyclerView como panel izquierdo y FragmentContainerView como vista detallada principal para mostrar el contenido en el panel izquierdo. De hecho, es similar a la interfaz de usuario que usa TwoPane en Compose descrita anteriormente.
<!-- two_pane.xml -->
<androidx.slidingpanelayout.widget.SlidingPaneLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sliding_pane_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The first child view becomes the left pane. When the combined
desired width (expressed using android:layout_width) would
not fit on-screen at once, the right pane is permitted to
overlap the left. -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_pane"
android:layout_width="280dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
<!-- The second child becomes the right (content) pane. In this
example, android:layout_weight is used to expand this detail pane
to consume leftover available space when the
the entire window is wide enough to fit both the left and right pane.-->
<androidx.fragment.app.FragmentContainerView
android:id="@+id/detail_container"
android:layout_width="300dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:background="#ff333333"
android:name="com.example.SelectAnItemFragment" />
</androidx.slidingpanelayout.widget.SlidingPaneLayout>
También SlidingPaneLayout
funciona con Navigation
elementos Fragment para administrar y ahora también reconoce y se adapta a estados plegados y articulados, por ejemplo:
El uso de un dispositivo con una bisagra que cubre parte de la pantalla coloca automáticamente el contenido de la aplicación en ambos lados.
SlidingPaneLayout
El modo de bloqueo también se introduce para permitir controlar el comportamiento de deslizamiento cuando los paneles se superponen, por ejemplo:
Para evitar que el usuario se deslice hacia un panel vacío, es necesario hacer clic en un elemento de la lista para cargar información sobre ese panel, pero permitirle volver a la lista, en dispositivos plegables o tabletas donde hay espacio para mostrar dos vistas una al lado de la otra. lado, se ignorará el modo de bloqueo.
Ver más en: https://developer.android.com/guide/topics/ui/layout/twopane?hl=zh-cn
adaptación personalizada
Además del esquema de adaptación oficial, quizás necesitemos un esquema de adaptación personalizado más flexible, por lo que lo primero que debemos saber es cómo identificar la mampara plegable.
Identificar biombo
Jetpack WindowManager, que sigue siendo el mencionado Jetpack WindowManager, FoldingFeature
proporciona tipos de información sobre pantallas plegables, que incluyen:
state
: El estado plegado del dispositivoFLAT
(completamente abierto) oHALF_OPENED
(a medio camino entre los estados abierto y cerrado)orientation
: la dirección del pliegue o bisagra,HORIZONTAL
oVERTICAL
occlusionType
: Si el pliegue o la bisagra oculta parte de la pantallaNONE
(sin obstáculos) uFULL
(obstruido)isSeparating
: Si el pliegue o la bisagra crean dos áreas de visualización, verdadero (medio abierto/pantalla doble) o falso
Android 11 oficialmente también brinda soporte para leer el ángulo de plegado: el nuevo tipo TYPE_HINGE_ANGLE admite y el nuevo puede monitorear el ángulo de la bisagra y proporcionar la medición del ángulo entre las dos partes del dispositivo:SensorEvent
SensorEvent
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
hingeAngleSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
En cuanto a la postura de la mampara plegable, podemos Jetpack WindowManager
conseguirla mediante la API de:
-
El dispositivo está en modo TableTop con la pantalla medio abierta y la bisagra en orientación horizontal.
fun isTableTopMode(foldFeature: FoldingFeature) = foldFeature.isSeparating && foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
-
Dispositivo en modo Libro con pantalla medio abierta y bisagra en orientación vertical
fun isBookMode(foldFeature: FoldingFeature) = foldFeature.isSeparating && foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
Por ejemplo, el equipo de Google Duo utiliza Jetpack WindowManager para identificar el estado de la pantalla plegada y luego ajusta la interfaz de usuario durante el proceso de reproducción de acuerdo con el estado desplegada.
Brevemente, se obtiene a través de la biblioteca WindowManager durante la inicialización Flow<WindowLayoutInfo>
para informarle al teléfono que se encuentra actualmente en modo de escritorio y cómo obtener la posición plegada:
override fun onStart() {
super.onStart()
initializePlayer()
layoutUpdatesJob = uiScope.launch {
windowInfoRepository.windowLayoutInfo
.collect {
newLayoutInfo ->
onLayoutInfoChanged(newLayoutInfo)
}
}
}
override fun onStop() {
super.onStop()
layoutUpdatesJob?.cancel()
releasePlayer()
}
Cada vez que obtiene nueva información de diseño, puede consultar las capacidades de la pantalla y verificar si el dispositivo tiene pliegues o bisagras en la pantalla actual:
private fun onLayoutInfoChanged(newLayoutInfo: WindowLayoutInfo) {
if (newLayoutInfo.displayFeatures.isEmpty()) {
// The display doesn't have a display feature, we may be on a secondary,
// non foldable-screen, or on the main foldable screen but in a split-view.
centerPlayer()
} else {
newLayoutInfo.displayFeatures.filterIsInstance(FoldingFeature::class.java)
.firstOrNull {
feature -> isInTabletopMode(feature) }
?.let {
foldingFeature ->
val fold = foldPosition(binding.root, foldingFeature)
foldPlayer(fold)
} ?: run {
centerPlayer()
}
}
}
Si la orientación es horizontal y FoldingFeature.isSeparating()
devuelve verdadero, el dispositivo se puede usar en modo de escritorio, en cuyo caso se puede calcular la posición relativa del pliegue y mover el control a esa posición; de lo contrario, se mueve a 0 (parte inferior de la pantalla). .
private fun centerPlayer() {
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, 0)
binding.playerView.useController = true // use embedded controls
}
private fun foldPlayer(fold: Int) {
ConstraintLayout.getSharedValues().fireNewValue(R.id.fold, fold)
binding.playerView.useController = false // use custom controls
}
adaptación del tamaño de la ventana
En la adaptación de dispositivos plegables, la adquisición del tamaño de la ventana también es muy importante . Sin embargo, de hecho, desde el desarrollo de Android, algunas API han quedado obsoletas o todavía se utilizan incorrectamente. Para la adaptación de configuraciones de pantalla grande, Debido a que existen situaciones como Letterboxing, de hecho, la antigua API ya no puede satisfacer las necesidades.
Las API de Display actualmente obsoletas y a menudo mal utilizadas son:
- obtenerMetricas()
- obtenerTamaño()
- obtenerMetricasReales()
- obtenerTamañoReal()
- obtenerTamañoRect()
- obtenerAncho()
- obtener altura()
Las API de View que se utilizan de forma indebida son:
- getWindowVisibleDisplayFrame()
- obtenerUbicación en pantalla
Por ejemplo, y Display
han quedado obsoletos en API 30 en favor de nuevos métodos.getSize()
getMetrics()
WindowManager
Android 12 (API 31) deja de estar disponible Display
y métodos más nuevos getRealSize()
y getRealMetrics()
relacionados .getMaximumWindowMetrics()
Debido a que el tamaño real de su aplicación no es necesariamente consistente con el tamaño real de la pantalla en pantallas plegables y pantallas múltiples, no puede confiar en el tamaño de la pantalla física para ubicar los elementos de la interfaz de usuario. Ahora se recomienda confiar en la API de WindowMetrics :
- Plataforma:
- getCurrentWindowMetrics()
- getMaximumWindowMetrics()
- Mochila propulsora:
- Calculadora de WindowMetrics#computeCurrentWindowMetrics()
- Calculadora de WindowMetrics#computeMaximumWindowMetrics()
La plataforma aquí es que Android 11 (API 30) introdujo WindowManager
el método para proporcionar límites para las aplicaciones que se ejecutan en modo de ventanas múltiples:
getCurrentWindowMetrics()
: Devuelve el objeto de estado de ventana actual del sistema.WindowMetrics
getMaximumWindowMetrics()
: Devuelve el estado de ventana máximo del sistema.WindowMetrics
Los métodos de la biblioteca Jetpack WindowManager computeCurrentWindowMetrics()
y, computeMaximumWindowMetrics()
respectivamente, proporcionan una funcionalidad similar, pero son compatibles con versiones anteriores hasta API 14.
val windowMetrics = context.createDisplayContext(display)
.createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
.getSystemService(WindowManager::class.java)
.maximumWindowMetrics
Por tanto, a través de esto WindowManager
, podemos gestionar dinámicamente el cambio de tamaño de la ventana y reconocer el cambio de la pantalla plegable, por ejemplo, para onConfigurationChanged()
configurar el diseño de la aplicación del tamaño de ventana actual:
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val windowMetrics = WindowMetricsCalculator.getOrCreate()
.computeCurrentWindowMetrics(this@MainActivity)
val bounds = windowMetrics.getBounds()
...
}
Finalmente, en cuanto a personalización y adaptación de ventanas, es un tema común, por ejemplo:
- Utilice
wrap_content
,match_parent
evite la codificación - Úselo para
ConstraintLayout
crear el diseño raíz, que es conveniente para cambios de tamaño de pantalla, y la vista se mueve y estira automáticamente - Establezca la propiedad de
application
o en el AndroidManifest de la aplicación para admitir el cambio de tamaño y el diseño responsivo/adaptativo.activity
android:resizeableActivity
true
res/layout/
Se pueden proporcionar diseños adaptables creando directorios como layout-w600dp- ·····
Múltiples ventanas y ciclo de vida.
Dado que la pantalla plegable está puramente en múltiples áreas, puede haber múltiples ventanas, o incluso más de dos ventanas, en este caso, naturalmente, habrá problemas de adaptación del ciclo de vida, como que varias aplicaciones accedan a la cámara al mismo tiempo.
Con respecto al proceso de ventanas múltiples, puede presentar brevemente:
-
Android 7.0 admite pantalla dividida: muestra dos ventanas a la izquierda y a la derecha/arriba y abajo
-
Android 8.0 admite el modo de imagen en imagen. En este momento, la imagen en imagen
Activity
está en primer plano, pero enPaused
estado -
Android 9.0 (API 28) y versiones anteriores: en ventanas múltiples, solo la aplicación enfocada está en el
Resumed
estado y otras visiblesActivity
todavía están en elPaused
estado -
Android 10.0 (API 29): en modo de ventanas múltiples, cada una
Acttivity
está enResumed
estado
Mira, el ciclo de vida es diferente en diferentes niveles de API , por lo que para resolver el problema de que solo la aplicación enfocada está en el estado de Android 9.0 e inferior Resume
, se pueden agregar los siguientes atributos en el lado de la aplicación y se admiten varios elementos. agregando manualmente Resumed
:
<meta-data
android:name="android.allow_multiple_resumed_activities" android:value="true" />
Se le conoce comúnmente como estado de reanudación múltiple.
Para admitir el estado de reanudación múltiple, naturalmente se requiere una nueva devolución de llamada del ciclo de vida, es decironTopResumedActivityChanged()
.
El sistema llama a este método cuando una actividad gana o pierde la posición superior de Reanudar, como cuando se utiliza un recurso único compartido, como un micrófono o una cámara:
override fun onTopResumedActivityChanged(topResumed: Boolean) {
if (topResumed) {
// Top resumed activity
// Can be a signal to re-acquire exclusive resources
} else {
// No longer the top resumed activity
}
}
Por ejemplo, para la escena que usa la cámara, para el paquete anterior, Android 10 (nivel de API 29) CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged()
proporciona un mensaje de devolución de llamada para indicar que puede ser el momento de intentar acceder a la cámara.
Es importante tener en cuenta aquí que el uso resizeableActivity=false
no garantiza el acceso exclusivo a la cámara , ya que otras aplicaciones que usan la cámara pueden estar abiertas en varios monitores (pantalla dividida).
CameraDevice.StateCallback#onDisconnected()
Por lo tanto, la aplicación necesita manejar comportamientos relacionados después de recibir la devolución de llamada. Si la API aún funciona después de onDisconnected, el sistema generará un archivo CameraAccessException
.
De hecho, siempre que haga un buen juicio a través de la devolución de llamada, esta experiencia de cambio de "enfoque" es perfecta.
En el modo de ventanas múltiples, Android puede deshabilitar o ignorar funciones que no son aplicables a actividades que comparten la pantalla del dispositivo con otras actividades o aplicaciones.
Además, Activity también proporciona algunos métodos para admitir el modo de ventanas múltiples:
-
isInMultiWindowMode()
Ya sea para estar en modo de ventanas múltiples. -
isInPictureInPictureMode()
Si la actividad está en modo imagen en imagen.Nota: El modo Imagen en imagen es un caso especial del modo de ventanas múltiples; si
isInPictureInPictureMode()
devuelve verdadero,isInMultiWindowMode()
también devolverá verdadero. -
onMultiWindowModeChanged()
El sistema llama a este método cuando la Actividad entra o sale del modo de ventanas múltiples.Si la Actividad ingresa al modo de ventanas múltiples, el sistema pasa a este método un valor de verdadero; si la Actividad sale del modo de ventanas múltiples, el sistema pasa a este método un valor de falso.
-
onPictureInPictureModeChanged()
El sistema llama a este método cuando la Actividad ingresa o sale del modo imagen en imagen.El sistema pasa a este método un valor verdadero si la Actividad ingresa al modo de imagen en imagen y un valor falso si la Actividad sale del modo de imagen en imagen.
Fragment también proporciona métodos similares, como Fragment.onMultiWindowModeChanged()
.
Aleteo
A partir de 3.13, Flutter también agregó una nueva API para coincidir con las diversas propiedades de la pantalla #41685 , donde el nuevo FlutterView.display devuelve un objeto Display , y el objeto Display informará el tamaño físico de la pantalla, la proporción de píxeles del dispositivo y la actualización. tasa:
void didChangeMetrics() {
final ui.Display? display = _display;
if (display == null) {
return;
}
if (display.size.width / display.devicePixelRatio < kOrientationLockBreakpoint) {
SystemChrome.setPreferredOrientations(<DeviceOrientation>[
DeviceOrientation.portraitUp,
]);
} else {
SystemChrome.setPreferredOrientations(<DeviceOrientation>[]);
}
}
El objetivo principal de esta nueva API es lo que se mencionó anteriormente, porque una vez que Flutter ingresa al modo Letterboxing, MediaQuery
es posible que Flutter no pueda obtener el tamaño completo de la pantalla disponible , por lo que la nueva API es proporcionar el tamaño real después de plegar y cambiar a Space. para que los desarrolladores se adapten.
Además, todavía se está sincronizando la compatibilidad con múltiples tamaños de pantalla en Flutter #125938、#125939 , si está interesado, también puede prestar atención.
por fin
Se puede ver que todas las personas aquí son camaradas muy pacientes. Esta encuesta involucra mucho contenido y cubre una amplia gama de puntos de conocimiento. Algunos pueden no ser lo suficientemente profundos. En general, todavía proporciona direcciones e ideas, que involucran principalmente:
- Representación del modo Letterboxing compatible
resizeableActivity
comportamiento diferente de configuraciones como- Esquema de adaptación para Compose /Activity Embedding /SlidingPaneLayout
- Juicio de pantalla plegable, adaptación de ventana y compatibilidad del ciclo de vida.
- API de aleteo
Creo que todavía hay muchas apps que no piensan adaptarse a la pantalla plegable, al fin y al cabo "no es imposible de usar", pero después de entender este artículo, al menos te puede dar algo de confianza, al menos eso parece. que si realmente quieres adaptarte, no es gran cosa. Cosas que no se pueden hacer.
Si tienes algo más que decir, bienvenido a dejar un comentario.