El siguiente material es para desarrolladores de apps.
Para que tu app admita un control rotativo, DEBES hacer lo siguiente:
- Coloca un elemento
FocusParkingView
en el diseño de la actividad correspondiente. - Asegúrate de que las vistas sean (o no) enfocables.
- Usa objetos
FocusArea
para agrupar todas las vistas enfocables, excepto laFocusParkingView
Cada una de estas tareas se detalla a continuación, después de configurar tu entorno para desarrollar apps habilitadas para rotativos.
Cómo configurar un control rotativo
Antes de comenzar a desarrollar apps habilitadas para rotaciones, necesitas un control rotativo o una sustitución. Tiene las opciones que se describen a continuación.
Emulador
source build/envsetup.sh && lunch car_x86_64-userdebug m -j emulator -wipe-data -no-snapshot -writable-system
También puedes usar aosp_car_x86_64-userdebug
.
Para acceder al control rotativo emulado, haz lo siguiente:
- Presiona los tres puntos en la parte inferior de la barra de herramientas:
- Selecciona Rotación del vehículo en la ventana de controles extendidos:
Teclado USB
- Conecta un teclado USB al dispositivo que ejecute el SO Android Automotive (AAOS). En algunos casos, haz lo siguiente: De esta forma, evitas que aparezca el teclado en pantalla.
- Usa una compilación
userdebug
oeng
. - Cómo habilitar el filtrado de eventos clave:
adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
- Consulta la siguiente tabla para encontrar la clave correspondiente para cada acción:
Clave Acción rotativa P Rotar en el sentido contrario a las manecillas del reloj E Giro en sentido horario A Empujar hacia la izquierda D Empujar hacia la derecha W Empujar hacia arriba S Empujar hacia abajo F o coma Centrar botón R o Esc Botón Atrás
Comandos de ADB
Puedes usar comandos car_service
para insertar eventos de entrada rotativos. Estos comandos
se puede ejecutar en dispositivos con el SO Android Automotive (AAOS) o en un emulador.
comandos de car_service | Entrada rotativa |
---|---|
adb shell cmd car_service inject-rotary |
Rotar en el sentido contrario a las manecillas del reloj |
adb shell cmd car_service inject-rotary -c true |
Giro en sentido horario |
adb shell cmd car_service inject-rotary -dt 100 50 |
Girar a la izquierda varias veces (hace 100 ms y hace 50 ms) |
adb shell cmd car_service inject-key 282 |
Empujar hacia la izquierda |
adb shell cmd car_service inject-key 283 |
Empujar hacia la derecha |
adb shell cmd car_service inject-key 280 |
Empujar hacia arriba |
adb shell cmd car_service inject-key 281 |
Empujar hacia abajo |
adb shell cmd car_service inject-key 23 |
Clic en el botón central |
adb shell input keyevent inject-key 4 |
Clic en el botón Atrás |
Control rotativo OEM
Cuando el hardware del control rotativo está funcionando, una opción más realista. Es particularmente útil para probar la rotación rápida.
VistaDeEstacionamientoConcentrado
FocusParkingView
es una vista transparente en la
Biblioteca de la IU del vehículo (car-ui-library).
RotaryService
lo usa para admitir la navegación del control rotativo.
FocusParkingView
debe ser la primera vista enfocable
en el diseño. Debe colocarse fuera de todos los elementos FocusArea
. Cada ventana debe tener una
FocusParkingView
Si ya usas el diseño base car-ui-library,
que contiene un FocusParkingView
, no necesitas agregar otro
FocusParkingView
A continuación, se muestra un ejemplo de FocusParkingView
en
RotaryPlayground
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <com.android.car.ui.FocusParkingView android:layout_width="wrap_content" android:layout_height="wrap_content"/> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout>
Estos son los motivos por los que necesitas un FocusParkingView
:
- Android no borra el enfoque automáticamente cuando el foco se establece en otra ventana. Si
cuando elimines el foco de la ventana anterior, Android volverá a enfocar una vista en esa ventana, lo que
da como resultado dos ventanas centradas al mismo tiempo. Agrega un
FocusParkingView
a cada ventana puede solucionar este problema. Esta vista es transparente y su enfoque predeterminado destaca está inhabilitado, de modo que sea invisible para el usuario, independientemente de si está enfocado o no. Puede tomar el foco para queRotaryService
pueda estacionar el foco en él. para quitar el enfoque. - Si solo hay un
FocusArea
en la ventana actual, se rotará el controlador. enFocusArea
hace queRotaryService
mueva el enfoque de la vista de la derecha a la de la izquierda (y viceversa). Agregando esta vista a cada ventana puede solucionar el problema. CuandoRotaryService
determina el enfoque objetivo es unFocusParkingView
, puede determinar que un ajuste está a punto de ocurren y evita el ajuste, ya que no mueve el foco. - Cuando el control rotativo inicia una app, Android enfoca la primera vista enfocable
que siempre es
FocusParkingView
. ElFocusParkingView
determina la vista óptima en la que enfocarse y, luego, aplica el enfoque.
Vistas enfocables
RotaryService
se basa en el framework de Android
existente
de enfoque visual, que se remonta a cuando los teléfonos tenían teclados físicos y pads direccionales.
El atributo android:nextFocusForward
existente se reutiliza para los anuncios rotativos
(consulta Personalización de FocusArea), pero
android:nextFocusLeft
, android:nextFocusRight
,
android:nextFocusUp
y android:nextFocusDown
no lo son.
RotaryService
solo se enfoca en las vistas enfocables. Algunas vistas
como los objetos Button
,
suelen ser enfocables. Otros, como TextView
y ViewGroup
,
normalmente no lo son. Las vistas en las que se puede hacer clic son enfocables automáticamente y las vistas se vuelven automáticamente
en el que se puede hacer clic cuando tienen un objeto de escucha de clics. Si esta lógica automática genera los resultados deseados
no necesitas establecer de forma explícita la enfocabilidad de la vista. Si la lógica automática no
resultado en la capacidad de enfoque deseada, establece el atributo android:focusable
en
true
o false
, o establece de manera programática la enfocabilidad de la vista con
View.setFocusable(boolean)
Para que RotaryService
se enfoque en ella, una vista DEBE
cumplan con los siguientes requisitos:
- Enfocable
- Habilitado
- Visible
- Tener valores distintos de cero para el ancho y la altura
Si una vista no cumple con todos estos requisitos (por ejemplo, un botón enfocable pero inhabilitado),
el usuario no puede usar el control rotativo para enfocarse en él. Si quieres enfocarte
en las vistas inhabilitadas,
considera usar un estado personalizado en lugar de android:state_enabled
para controlar cómo
la vista aparece sin indicar que Android debe considerarla inhabilitada. Tu app puede informar
al usuario por qué la vista se inhabilita cuando se la presiona. En la siguiente sección, se explica cómo hacerlo.
Estado personalizado
Para agregar un estado personalizado, sigue estos pasos:
- Para agregar un atributo personalizado
a tu vista. Por ejemplo, para agregar un estado
state_rotary_enabled
personalizado a la La clase de vistaCustomView
, usa:<declare-styleable name="CustomView"> <attr name="state_rotary_enabled" format="boolean" /> </declare-styleable>
- Para realizar un seguimiento de este estado, agrega una variable de instancia a tu vista junto con los métodos de acceso:
private boolean mRotaryEnabled; public boolean getRotaryEnabled() { return mRotaryEnabled; } public void setRotaryEnabled(boolean rotaryEnabled) { mRotaryEnabled = rotaryEnabled; }
- Para leer el valor del atributo cuando se crea la vista, haz lo siguiente:
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView); mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
- En tu clase de vistas, anula el método
onCreateDrawableState()
y, luego, agrega el estado personalizado, cuando corresponda. Por ejemplo:@Override protected int[] onCreateDrawableState(int extraSpace) { if (mRotaryEnabled) extraSpace++; int[] drawableState = super.onCreateDrawableState(extraSpace); if (mRotaryEnabled) { mergeDrawableStates(drawableState, { R.attr.state_rotary_enabled }); } return drawableState; }
- Haz que el controlador de clics de tu vista tenga un rendimiento diferente según su estado. Por ejemplo, el
es posible que el controlador de clics no haga nada o que aparezca un aviso cuando
mRotaryEnabled
esfalse
. - Para que el botón aparezca inhabilitado, en el elemento de diseño en segundo plano de tu vista, usa
app:state_rotary_enabled
en lugar deandroid:state_enabled
. Si aún no lo tienes, deberás agregar lo siguiente:xmlns:app="http://schemas.android.com/apk/res-auto"
- Si la vista está inhabilitada en algún diseño, reemplaza
android:enabled="false"
porapp:state_rotary_enabled="false"
y, luego, agrega el espacio de nombresapp
. como se muestra arriba. - Si la vista se inhabilita de manera programática, reemplaza las llamadas a
setEnabled()
. con llamadas asetRotaryEnabled()
.
Área de enfoque
Usa FocusAreas
para particionar las vistas enfocables en bloques de modo que la navegación
sea más fácil y coherente con otras apps. Por ejemplo, si tu app tiene una barra de herramientas, esta
debe estar en un FocusArea
independiente del resto de la app. Barras de pestañas y
los demás elementos de navegación también deben estar separados del resto de la app. Listas grandes
por lo general, deben tener su propio FocusArea
. De lo contrario, los usuarios deberán rotar
toda la lista para acceder a algunas vistas.
FocusArea
es una subclase de LinearLayout
en la biblioteca car-ui-ui.
Cuando esta función está habilitada, FocusArea
dibuja un resaltado cuando uno de sus
elementos subordinados. Para obtener más información, consulta
Personalización del enfoque destacado.
Al crear un bloque de navegación en el archivo de diseño, si deseas usar un
LinearLayout
como contenedor para ese bloque, usa FocusArea
en su lugar.
De lo contrario, une el bloque a una FocusArea
.
NO anides un FocusArea
en otro FocusArea
.
Hacerlo genera un comportamiento de navegación indefinido. Asegúrate de que todas las vistas enfocables
anidada dentro de un FocusArea
.
Un ejemplo de un FocusArea
en
RotaryPlayground
se muestra a continuación:
<com.android.car.ui.FocusArea android:layout_margin="16dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true"> </EditText> </com.android.car.ui.FocusArea>
FocusArea
funciona de la siguiente manera:
- Cuando controla las acciones de rotación y sugerencia,
RotaryService
busca instancias deFocusArea
en la jerarquía de vistas. - Cuando recibe un evento de rotación,
RotaryService
mueve el enfoque a otro Vista que se puede enfocar en el mismoFocusArea
. - Al recibir un evento de sugerencia,
RotaryService
mover el enfoque a otra vista que puede enfocarse en otroFocusArea
(por lo general, adyacente).
Si no incluyes ningún FocusAreas
en tu diseño, se tratará la vista raíz.
como un área de enfoque implícita. El usuario no puede sugerirle al usuario navegar en la app. Por el contrario,
roten por todas las vistas enfocables, lo que podría ser adecuado para los diálogos.
Personalización de FocusArea
Se pueden usar dos atributos de View estándares para personalizar la navegación rotativa:
android:nextFocusForward
permite que los desarrolladores de apps especifiquen la rotación. en un área de enfoque. Este es el mismo atributo que se usa para controlar el orden de tabulación de la navegación con el teclado. NO uses este atributo para crear un bucle. En su lugar, usaapp:wrapAround
(consulta a continuación) para crear un bucle.android:focusedByDefault
permite que los desarrolladores de apps especifiquen la predeterminada en la ventana. NO uses este atributo niapp:defaultFocus
(consulta a continuación) en el mismoFocusArea
.
FocusArea
también define algunos atributos para personalizar la navegación rotativa.
Las áreas de enfoque implícitas no se pueden personalizar con estos atributos.
- (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocus
se puede usar para especificar el ID de una vista descendente enfocable, en la que se debería enfocar cuando el usuario sugerencias a estaFocusArea
. - (Android 11 QPR3, Android 11 Car,
Android 12)
app:defaultFocusOverridesHistory
se puede establecer entrue
para que se enfoque la vista especificada anteriormente, incluso si para indicar otra vista de esteFocusArea
en la que se había enfocado. - (Android 12)
Usarapp:nudgeLeftShortcut
,app:nudgeRightShortcut
app:nudgeUpShortcut
yapp:nudgeDownShortcut
para especificar el ID de una vista descendente enfocable, en la que debería enfocarse cuando la el usuario hace el aporte en una dirección determinada. Para obtener más información, consulta el contenido de sugiere combinaciones de teclas a continuación.(Android 11 QPR3, Android 11 Car, obsoleto en Android 12)
app:nudgeShortcut
yapp:nudgeShortcutDirection
solo admitían una combinación de teclas de sugerencia. - (Android 11 QPR3, Android 11 Car,
Android 12)
Para habilitar la rotación para ajustar estaFocusArea
,app:wrapAround
se puede establecer entrue
. Por lo general, se usa cuando las vistas se organizan en una óvalo o círculo. - (Android 11 QPR3, Android 11 Car,
Android 12)
Para ajustar el relleno del resaltado en esteFocusArea
, usaapp:highlightPaddingStart
,app:highlightPaddingEnd
,app:highlightPaddingTop
app:highlightPaddingBottom
,app:highlightPaddingHorizontal
, yapp:highlightPaddingVertical
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Para ajustar los límites percibidos de esteFocusArea
a fin de encontrar un objetivo de sugerencia, usaapp:startBoundOffset
,app:endBoundOffset
app:topBoundOffset
,app:bottomBoundOffset
,app:horizontalBoundOffset
yapp:verticalBoundOffset
. - (Android 11 QPR3, Android 11 Car,
Android 12)
Para especificar explícitamente el ID de unFocusArea
adyacentes (o áreas) en las indicaciones dadas, utilizaapp:nudgeLeft
,app:nudgeRight
,app:nudgeUp
yapp:nudgeDown
Úsala cuando se use la búsqueda geométrica de forma predeterminada no encuentra el objetivo deseado.
Por lo general, los comentarios permiten navegar entre FocusAreas. Pero, con los atajos de sugerencias,
Las sugerencias a veces navegan primero dentro de un FocusArea
para que el usuario pueda necesitar
para navegar dos veces a la siguiente FocusArea
. Las combinaciones de teclas son útiles
cuando un elemento FocusArea
contiene una lista larga seguida de un
Botón de acción flotante,
como en el siguiente ejemplo:
Sin el atajo de sugerencia, el usuario tendría que rotar toda la lista para llegar a el FAB.
Enfocar la personalización del momento destacado
Como se indicó anteriormente, RotaryService
se basa en el concepto existente de framework de Android
enfoque de vista. Cuando el usuario rota y empuja, RotaryService
mueve el foco,
enfocar una vista y dejar de enfocar otra. En Android, cuando una vista está enfocada, si la vista:
- Si especificó su propio punto destacado, Android lo dibuja con la vista.
- No especifica el enfoque destacado ni el predeterminado está inhabilitado. dibuja el enfoque predeterminado para la vista.
Por lo general, las apps diseñadas para el uso táctil no especifican los aspectos destacados del enfoque adecuado.
El framework de Android proporciona el enfoque predeterminado, que se puede anular.
por el OEM. Los desarrolladores de apps lo reciben cuando el tema que usan se deriva de
Theme.DeviceDefault
Para ofrecer una experiencia del usuario coherente, usa el enfoque predeterminado cuando sea posible.
Si necesitas un enfoque con forma personalizada (por ejemplo, redonda o con forma de píldora), o si quieres
con un tema no derivado de Theme.DeviceDefault
, usa car-ui-library
para especificar tu propio enfoque destacado para cada vista.
Para especificar un enfoque personalizado destacado para una vista, cambia el elemento de diseño en primer o segundo plano de la vista a un elemento de diseño que difiere cuando se enfoca la vista. Por lo general, cambiarías segundo plano. El siguiente elemento de diseño, si se usa como fondo para una vista cuadrada, produce un enfoque redondo destacado:
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" android:state_pressed="true"> <shape android:shape="oval"> <solid android:color="@color/car_ui_rotary_focus_pressed_fill_color"/> <stroke android:width="@dimen/car_ui_rotary_focus_pressed_stroke_width" android:color="@color/car_ui_rotary_focus_pressed_stroke_color"/> </shape> </item> <item android:state_focused="true"> <shape android:shape="oval"> <solid android:color="@color/car_ui_rotary_focus_fill_color"/> <stroke android:width="@dimen/car_ui_rotary_focus_stroke_width" android:color="@color/car_ui_rotary_focus_stroke_color"/> </shape> </item> <item> <ripple...> ... </ripple> </item> </selector>
(Android 11 QPR3, Android 11 Car, Android 12) Referencias de recursos negrita en la muestra de arriba identifican los recursos definidos por la biblioteca car-ui-library. El OEM los anula para que sean coherentes. con el enfoque predeterminado que especifique. Esto garantiza que el color de resaltado del enfoque, ancho del trazo, y así sucesivamente, no cambian cuando el usuario navega entre una vista con un enfoque personalizado y una vista con el enfoque predeterminado. El último elemento es una onda utilizada para el tacto. Los valores predeterminados usados para los recursos en negrita aparecen de la siguiente manera:
Además, se llama a un enfoque personalizado destacado cuando se le da un botón sólido color de fondo para llamar la atención del usuario, como en el siguiente ejemplo. Esto puede hacer que el el enfoque destacado es difícil de ver. En este caso, especifica un enfoque destacado personalizado con secondary (secundarios):
- (Android 11 QPR3, Android 11 Car,
Android 12)
car_ui_rotary_focus_fill_secondary_color
car_ui_rotary_focus_stroke_secondary_color
- (Android 12)
car_ui_rotary_focus_pressed_fill_secondary_color
car_ui_rotary_focus_pressed_stroke_secondary_color
Por ejemplo:
Enfocado, no presionado | Enfocado, presionado |
Desplazamiento rotativo
Si tu app usa objetos RecyclerView
, DEBERÍAS usar
CarUiRecyclerView
en su lugar. Esto garantiza que tu IU sea coherente con
Otros porque la personalización de un OEM se aplica a todos los CarUiRecyclerView
.
Si todos los elementos de tu lista son enfocables, no necesitas hacer nada más. La navegación rotativa mueve el foco entre los elementos de la lista y esta se desplaza para que el elemento enfocado recientemente sea visible.
(Android 11 QPR3, Android 11 Car,
Android 12)
Si hay una combinación
de enfoque y no enfocable
o, si todos los elementos no son enfocables, puedes habilitar el desplazamiento rotativo, que
el usuario debe usar el control rotativo para desplazarse gradualmente por la lista sin omitir
elementos que no se pueden enfocar. Para habilitar el desplazamiento rotativo, configura app:rotaryScrollEnabled
a true
.
(Android 11 QPR3, Android 11 Car,
Android 12)
Puedes habilitar el desplazamiento rotativo en cualquier
vista desplazable, incluida avCarUiRecyclerView
, con la
setRotaryScrollEnabled()
en CarUiUtils
. Si lo haces,
tendrás que hacer lo siguiente:
- Haz que la vista desplazable sea enfocable para que pueda enfocarse en cuando ninguno de sus las vistas descendentes enfocables son visibles,
- Inhabilita el enfoque predeterminado para destacar en la vista desplazable llamando a
setDefaultFocusHighlightEnabled(false)
para que la vista desplazable no parece estar enfocada, - Asegúrate de que la vista desplazable se enfoque antes de sus elementos subordinados llamando a
setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS)
- Escucha MotionEvents con
SOURCE_ROTARY_ENCODER
y cualquiera de los dos:AXIS_VSCROLL
oAXIS_HSCROLL
para indicar la distancia de desplazamiento y la dirección (a través del letrero).
Cuando el desplazamiento rotativo está habilitado en una CarUiRecyclerView
y el usuario rota
a un área en la que no hay vistas enfocables, la barra de desplazamiento cambia de gris a azul, como si
para indicar que la barra de desplazamiento está enfocada. Si lo deseas, puedes implementar un efecto similar.
Los MotionEvents son los mismos que los generados por la rueda de desplazamiento del mouse. excepto por la fuente.
Modo de manipulación directa
Por lo general, las sugerencias y la rotación navegan por la interfaz de usuario mientras se presiona el botón central. tomar medidas, aunque no siempre es así. Por ejemplo, si un usuario desea ajustar el puede usar el control rotativo para navegar hasta el control deslizante del volumen, presionar Botón central, rota el control para ajustar el volumen de la alarma y presiona el botón Atrás para volver a la navegación. Esto se conoce como modo de manipulación directa (DM). En este , el control rotativo se usa para interactuar con la vista directamente en lugar de navegar.
Implementar la DM de dos maneras. Si solo necesitas controlar la rotación y la vista que deseas
manipular las respuestas a ACTION_SCROLL_FORWARD
y
ACTION_SCROLL_BACKWARD
AccessibilityEvent
correctamente, usa el
mecanismo simple. De lo contrario, usa el mecanismo avanzado.
El mecanismo simple es la única opción en las ventanas del sistema. las aplicaciones pueden usar cualquiera de los dos mecanismos.
Mecanismo simple
(Android 11 QPR3, Android 11 Car,
Android 12)
Tu app debería llamar
DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable)
RotaryService
reconoce cuando el usuario está en modo de MD y entra en modo de DM cuando el usuario está en ese modo
presiona el botón Centro mientras una vista está enfocada. En el modo de DM, las rotaciones realizan
ACTION_SCROLL_FORWARD
o ACTION_SCROLL_BACKWARD
y sale del modo de MD
cuando el usuario presiona el botón Atrás. El mecanismo simple activa o desactiva el estado seleccionado de
la vista al ingresar y salir del modo de DM.
Para proporcionar un indicador visual de que el usuario está en modo DM, haz que tu vista se vea diferente.
cuando se seleccionan. Por ejemplo, cambia el fondo cuando
android:state_selected
es true
.
Mecanismo avanzado
La app determina en qué momento RotaryService
entra y sale del modo de MD. Para obtener una experiencia
experiencia del usuario, presionar el botón Centro con una vista de DM enfocada debería ingresar al modo de DM
y el botón Atrás debería salir del modo DM. Si no se usan el botón Centrar o la sugerencia,
pueden ser formas alternativas de salir del modo de MD. Para apps como Maps, un botón para representar
Se puede usar un MD para ingresar al modo de MD.
Para admitir el modo de MD avanzado, una vista tiene las siguientes características:
- (Android 11 QPR3, Android 11 Car,
Android 12) DEBE escuchar un
KEYCODE_DPAD_CENTER
. para ingresar al modo DM y escuchar un eventoKEYCODE_BACK
para salir del modo DM, llamando aDirectManipulationHelper.enableDirectManipulationMode()
en cada caso. Para escuchar estos eventos, realiza una de las siguientes acciones:- Registra un
OnKeyListener
.
o
- Extiende la vista y, luego, anula su método
dispatchKeyEvent()
.
- Registra un
- SE RECOMIENDA escuchar los eventos de sugerencia (
KEYCODE_DPAD_UP
,KEYCODE_DPAD_DOWN
,KEYCODE_DPAD_LEFT
oKEYCODE_DPAD_RIGHT
) si la vista debe administrar las sugerencias. - SE DEBE escuchar los
MotionEvent
y obtener el recuento de rotación enAXIS_SCROLL
si la vista quiere controlar la rotación. Existen varias formas de hacerlo:- Registra un
OnGenericMotionListener
. - Extiende la vista y anula su método
dispatchTouchEvent()
.
- Registra un
- Para evitar quedar atascado en el modo DM, DEBES salir de este modo cuando el fragmento o la actividad de la vista al que pertenece no es interactivo.
- SE DEBE proporcionar un indicador visual para indicar que la vista está en modo de MD.
A continuación, se proporciona un ejemplo de una vista personalizada que utiliza el modo DM para desplazarse lateralmente y hacer zoom en un mapa:
/** Whether this view is in DM mode. */ private boolean mInDirectManipulationMode;
/** Initializes the view. Called by the constructors. */ private void init() { setOnKeyListener((view, keyCode, keyEvent) -> { boolean isActionUp = keyEvent.getAction() == KeyEvent.ACTION_UP; switch (keyCode) { // Always consume KEYCODE_DPAD_CENTER and KEYCODE_BACK events. case KeyEvent.KEYCODE_DPAD_CENTER: if (!mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = true; DirectManipulationHelper.enableDirectManipulationMode(this, true); setSelected(true); // visually indicate DM mode } return true; case KeyEvent.KEYCODE_BACK: if (mInDirectManipulationMode && isActionUp) { mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); setSelected(false); } return true; // Consume controller nudge events only when in DM mode. // When in DM mode, nudges pan the map. case KeyEvent.KEYCODE_DPAD_UP: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, -10f); return true; case KeyEvent.KEYCODE_DPAD_DOWN: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(0f, 10f); return true; case KeyEvent.KEYCODE_DPAD_LEFT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(-10f, 0f); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!mInDirectManipulationMode) return false; if (isActionUp) pan(10f, 0f); return true; // Don't consume other key events. default: return false; } });
// When in DM mode, rotation zooms the map. setOnGenericMotionListener(((view, motionEvent) -> { if (!mInDirectManipulationMode) return false; float scroll = motionEvent.getAxisValue(MotionEvent.AXIS_SCROLL); zoom(10 * scroll); return true; })); }
@Override public void onPause() { if (mInDirectManipulationMode) { // To ensure that the user doesn't get stuck in DM mode, disable DM mode // when the fragment is not interactive (e.g., a dialog shows up). mInDirectManipulationMode = false; DirectManipulationHelper.enableDirectManipulationMode(this, false); } super.onPause(); }
Puedes encontrar más ejemplos en el
RotaryPlayground
proyecto.
Vista de actividad
Cuando uses un objeto ActivityView:
- El
ActivityView
no debe ser enfocable. - (Android 11 QPR3, Android 11 Car,
obsoleto en Android 11)
El contenido deActivityView
DEBE incluir unFocusParkingView
. como la primera vista enfocable y suapp:shouldRestoreFocus
el atributo DEBE serfalse
. - El contenido de
ActivityView
no debe tenerandroid:focusByDefault
vistas.
Para el usuario, ActivityViews no debería tener ningún efecto en la navegación, excepto ese enfoque.
áreas no pueden abarcar ActivityViews. En otras palabras, no puedes tener
una única área de enfoque
tiene contenido dentro y fuera de ActivityView
. Si no agregas
cualquier FocusAreas a tu ActivityView
, la raíz de la jerarquía de vistas en la
ActivityView
se considera un área de enfoque implícita.
Botones que funcionan cuando se presionan
La mayoría de los botones causan alguna acción cuando se hace clic en ellos. Algunos botones funcionan cuando se mantienen presionados.
Por ejemplo, los botones de avance y retroceso suelen funcionar cuando se mantienen presionados. Para que este
Los botones admiten el control rotativo; escucha KEYCODE_DPAD_CENTER
KeyEvents
.
de la siguiente manera:
mButton.setOnKeyListener((v, keyCode, event) -> { if (keyCode != KEYCODE_DPAD_CENTER) { return false; } if (event.getAction() == ACTION_DOWN) { mButton.setPressed(true); mHandler.post(mRunnable); } else { mButton.setPressed(false); mHandler.removeCallbacks(mRunnable); } return true; });
En el que mRunnable
realiza una acción (como retroceder) y se programa para
ejecutarse después de una demora.
Modo táctil
Los usuarios pueden usar un control rotativo para interactuar con la consola central en un vehículo de dos maneras: usando el control rotativo o tocando la pantalla. Cuando uses el control rotativo, se destaca una de las vistas enfocables. No enfocar la pantalla cuando se toca la pantalla . El usuario puede cambiar entre estos modos de entrada en cualquier momento:
- Rotatorio → táctil. Cuando el usuario toca la pantalla, desaparece el enfoque destacado.
- Tocar → rotativo. Cuando el usuario empuja, rota o presiona el botón central, los aparecerá el enfoque destacado.
Los botones Atrás y Inicio no tienen efecto en el modo de entrada.
Refuerzos rotativos sobre el concepto existente de Android
modo táctil.
Puedes usar
View.isInTouchMode()
para determinar qué modo de entrada usa. Puedes usar
OnTouchModeChangeListener
para detectar los cambios. Si bien esto se puede usar para personalizar la interfaz de usuario
modo de entrada de texto, evita los cambios importantes, ya que pueden ser desconcertantes.
Solución de problemas
En una app diseñada para el tacto, es común tener vistas enfocables anidadas.
Por ejemplo, puede haber una FrameLayout
alrededor de una ImageButton
,
ambas son enfocables. No daña el tacto, pero puede provocar una mala
de la experiencia del usuario para el control rotativo porque debe rotar el control dos veces para avanzar a
la siguiente vista interactiva. Para una buena experiencia del usuario, Google recomienda que hagas lo siguiente:
la vista externa o interna enfocable, pero no ambas.
Si un botón o interruptor pierde el foco cuando se presiona a través del control rotativo, una de las podrían aplicarse estas condiciones:
- El botón o interruptor se está inhabilitando (de forma breve o indefinida) debido al
que se presiona el botón. En cualquier caso, hay dos formas de abordar esto:
- Deja el estado
android:enabled
comotrue
y usa un valor personalizado. para inhabilitar el botón o el interruptor, como se describe en Estado personalizado. - Usa un contenedor para rodear el botón o interruptor y hacer que el contenedor sea enfocable en lugar del botón o interruptor. (El objeto de escucha de clics debe estar en el contenedor).
- Deja el estado
- Se reemplazará el botón o interruptor. Por ejemplo, la acción que se realiza cuando el botón
esté presionado o que el interruptor se active, es posible que se active una actualización de las acciones disponibles
lo que causa que los nuevos botones reemplacen a los existentes. Existen dos maneras de solucionar este problema:
- En lugar de crear un nuevo botón o interruptor, establece el ícono o el texto del botón o interruptor existente.
- Como se muestra más arriba, agrega un contenedor enfocable alrededor del botón o interruptor.
Parque de juegos rotativo
RotaryPlayground
es una app de referencia para rotativos. Úsalo para aprender a integrar
rotativas en tus apps. RotaryPlayground
se incluye en las compilaciones del emulador y en
compilaciones para dispositivos que ejecutan el SO Android Automotive (AAOS).
- Repositorio
RotaryPlayground
:packages/apps/Car/tests/RotaryPlayground/
- Versiones: Android 11 QPR3, Android 11 Car, y Android 12
La app de RotaryPlayground
muestra las siguientes pestañas a la izquierda:
- Tarjetas Prueba la navegación por las áreas de enfoque y omite los elementos no enfocables y la entrada de texto.
- Manipulación directa. Prueba widgets que admiten funciones simples y avanzadas de manipulación directa. Esta pestaña es específicamente para la manipulación directa dentro de la ventana de la app.
- Manipulación de la IU de sistemas. Probar widgets que admitan la manipulación directa en ventanas de sistema donde solo se admite el modo simple de manipulación directa
- Cuadrícula. Probar la navegación rotativa del patrón z con desplazamiento
- Notificación. Prueba sugerencias para entrar y salir de las notificaciones de atención.
- Desplázate. Prueba el desplazamiento con una combinación de elementos enfocables y no enfocables contenido.
- WebView. Prueba la navegación por vínculos en un
WebView
. FocusArea
personalizado. Prueba la personalización deFocusArea
:- Ajuste.
android:focusedByDefault
yapp:defaultFocus
.
- Objetivos explícitos de sugerencia.
- Sugerir combinaciones de teclas
FocusArea
sin vistas enfocables.