Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Desarrollo de aplicaciones

El siguiente material es para desarrolladores de aplicaciones.

Para que su aplicación sea compatible con rotary, DEBE:

  1. Coloque una FocusParkingView en el diseño de la actividad respectiva.
  2. Asegúrese de que las vistas sean (o no) enfocables.
  3. Uso FocusArea s para envolver alrededor de todos sus puntos de vista enfocable, excepto el FocusParkingView .

Cada una de estas tareas se detalla a continuación, una vez que haya configurado su entorno para desarrollar aplicaciones habilitadas para rotación.

Configurar un controlador rotatorio

Antes de que pueda comenzar a desarrollar aplicaciones habilitadas rotativamente, necesita un controlador rotatorio o un suplente. 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 puede utilizar aosp_car_x86_64-userdebug .

Para acceder al controlador rotatorio emulado:

  1. Toque los tres puntos en la parte inferior de la barra de herramientas:

    Acceda al controlador rotatorio emulado
    Figura 1. Acceso emulado regulador giratorio
  2. Seleccionar rotatorio de coches en la ventana de controles extendida:

    Seleccionar coche rotativo
    Figura giratorio 2. Seleccione Car

Teclado USB

  • Conecte un teclado USB a su Seahawk (en algunos casos, esto puede evitar que aparezca el teclado en pantalla).
  • Utilice una userdebug o eng acumulación.
  • Habilitar el filtrado evento clave:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • Consulte la tabla a continuación para encontrar la clave correspondiente a cada acción:
    Llave Acción rotatoria
    Q Girar en sentido antihorario
    mi Rotar las agujas del reloj
    A Empujar hacia la izquierda
    D Empujar a la derecha
    W Empujar hacia arriba
    S Empujar hacia abajo
    F o coma Botón central
    R o Esc Botón de retroceso

Comandos ADB

Puede utilizar car_service comandos para inyectar eventos de entrada rotativos. Estos comandos se pueden ejecutar en un Seahawk o en un emulador.

comandos car_service Entrada giratoria
adb shell cmd car_service inject-rotary Girar en sentido antihorario
adb shell cmd car_service inject-rotary -c true Rotar las agujas del reloj
adb shell cmd car_service inject-rotary -dt 100 50 Gire en sentido antihorario 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 a 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 Haga clic en el botón central
adb shell input keyevent inject-key 4 Haga clic en el botón Atrás

Controlador rotativo OEM

Cuando el hardware de su controlador giratorio está en funcionamiento, esta es la opción más realista. Es particularmente útil para probar la rotación rápida.

FocusParkingView

FocusParkingView es una vista transparente en la interfaz de usuario de la Biblioteca de coches (coche-ui-biblioteca) . RotaryService lo utiliza para apoyar la navegación regulador giratorio. FocusParkingView debe ser el primer punto de vista enfocable en el diseño. Debe ser colocado fuera de toda FocusArea s. Cada ventana debe tener una FocusParkingView . Si ya está utilizando el diseño base del coche-ui-biblioteca, que contiene una FocusParkingView , no es necesario añadir 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>

Estas son las razones por las que necesita un FocusParkingView :

  1. Android no borra el enfoque automáticamente cuando el enfoque se establece en otra ventana. Si intenta borrar el enfoque en la ventana anterior, Android reenfoca una vista en esa ventana, lo que da como resultado que dos ventanas se enfoquen simultáneamente. La adición de un FocusParkingView a cada ventana puede solucionar este problema. Esta vista es transparente y su resaltado de enfoque predeterminado está deshabilitado, por lo que es invisible para el usuario sin importar si está enfocado o no. Puede tomar enfoque para que RotaryService puede aparcar el foco en él para quitar el resaltado de enfoque.
  2. Si sólo hay un FocusArea en la ventana actual, girando el mando en el FocusArea causa RotaryService para mover el foco de la vista de la derecha a la vista de la izquierda (y viceversa). Agregar esta vista a cada ventana puede solucionar el problema. Cuando RotaryService determina el objetivo de enfoque es un FocusParkingView , se puede determinar una envolvente está a punto de ocurrir en cuyo punto se evita la envolvente por no se mueve el foco.
  3. Cuando se inicie el control giratorio de una aplicación, Android se centra la primera vista enfocable, que es siempre el FocusParkingView . El FocusParkingView determina la visión más adecuada de enfocar y luego se aplica el enfoque.

Vistas enfocables

RotaryService se basa en el marco de Android existentes concepto de Vista de la concentración, que se remonta a cuando los teléfonos tenían teclados físicos y D-pads. El actual android:nextFocusForward atributo se diseñarse para su rotación (véase la personalización FocusArea ), pero android:nextFocusLeft , android:nextFocusRight , android:nextFocusUp y android:nextFocusDown no lo son.

RotaryService sólo se centra en las vistas que son enfocable. Algunos puntos de vista, como el Button s, son por lo general enfocable. Otros, como TextView s y ViewGroup s, por lo general no lo son. Las vistas en las que se puede hacer clic se pueden enfocar automáticamente y las vistas se pueden hacer clic automáticamente cuando tienen un oyente de clics. Si esta lógica automática da como resultado la capacidad de enfoque deseada, no es necesario establecer explícitamente la capacidad de enfoque de la vista. Si la lógica automática no da como resultado la focusability deseada, establecer el android:focusable atributo a true o false focusability de la vista, o establecer mediante programación con View.setFocusable(boolean) . Para RotaryService para centrarse en ella, una vista debe cumplir con los siguientes requisitos:

  • Enfocable
  • Activado
  • Visible
  • Tener valores distintos de cero para el ancho y el alto.

Si una vista no cumple con todos estos requisitos, por ejemplo, un botón enfocable pero deshabilitado, el usuario no puede usar el control giratorio para enfocarse en ella. Si desea centrarse en vistas de movilidad reducida, considerar el uso de un estado a medida en lugar de android:state_enabled para controlar cómo aparece la vista sin indicar que Android debería considerar desactivado. Su aplicación puede informar al usuario por qué la vista está deshabilitada cuando se toca. La siguiente sección explica cómo hacer esto.

Estado personalizado

Para agregar un estado personalizado:

  1. Para agregar un atributo personalizado a la vista. Por ejemplo, para añadir un state_rotary_enabled estado personalizado a la CustomView vista de clase, uso:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. Para realizar un seguimiento de este estado, añadir una variable de instancia a la vista, junto con métodos de acceso:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. Para leer el valor de su atributo cuando se crea la vista:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. En la clase de vista, anular el onCreateDrawableState() método y luego agregar el estado personalizado, cuando sea apropiado. 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;
    }
    
  5. Haga que el controlador de clics de su vista funcione de manera diferente según su estado. Por ejemplo, el controlador de clic podría hacer nada ya que podría saltar hasta una tostada cuando mRotaryEnabled es false .
  6. Para hacer que el botón aparece desactivado, en vista de su fondo estirable, el uso app:state_rotary_enabled en lugar de android:state_enabled . Si no lo tiene, tendrá que añadir:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. Si su vista está desactivada en cualquier diseños, reemplace android:enabled="false" con la app:state_rotary_enabled="false" y luego añadir la app de espacio de nombres, como el anterior.
  8. Si su vista es mediante programación discapacitados, sustituir las llamadas a setEnabled() con llamadas a setRotaryEnabled() .

Area de enfoque

Use FocusAreas a particionan las vistas enfocable en bloques para facilitar la navegación y para ser coherente con otras aplicaciones. Por ejemplo, si su aplicación tiene una barra de herramientas, la barra de herramientas debe ser separada en un FocusArea del resto de su aplicación. Las barras de pestañas y otros elementos de navegación también deben estar separados del resto de la aplicación. Listas de gran tamaño por lo general deben tener su propia FocusArea . De lo contrario, los usuarios deben rotar por toda la lista para acceder a algunas vistas.

FocusArea es una subclase de LinearLayout en el coche-ui-biblioteca. Cuando esta función está activada, un FocusArea dibujará un punto culminante cuando uno de sus descendientes se centra. Para obtener más información, consulte la personalización más destacado de enfoque .

Al crear un bloque de navegación en el archivo de diseño, si la intención de utilizar un LinearLayout como un contenedor para ese bloque, utilice un FocusArea lugar. De lo contrario, situar el bloque en un FocusArea .

No anide un FocusArea en otro FocusArea . Hacerlo conducirá a un comportamiento de navegación indefinido. Asegúrese de que todos los puntos de vista enfocable se anidan 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:

  1. Al manipular rotación y empujar acciones, RotaryService busca instancias de FocusArea en la jerarquía de vistas.
  2. Cuando se recibe un evento de rotación, RotaryService mueve el foco a otro punto de vista que puede tomar el enfoque de la misma FocusArea .
  3. Cuando se recibe un evento empujón, RotaryService Mover el enfoque a otra vista que puede tomar foco en otro (típicamente adyacente) FocusArea .

Si no se incluye ninguna FocusAreas en su diseño, la vista de la raíz es tratado como un área de enfoque implícito. El usuario no puede empujar para navegar en la aplicación. En su lugar, rotarán a través de todas las vistas enfocables, lo que puede ser adecuado para los diálogos.

Personalización de FocusArea

Se pueden utilizar dos atributos de vista estándar para personalizar la navegación giratoria:

  • android:nextFocusForward permite a los desarrolladores de aplicaciones para especificar el orden de rotación en un área de enfoque. Este es el mismo atributo que se utiliza para controlar el orden de tabulación para la navegación con el teclado. NO utilice este atributo para crear un bucle. En su lugar, el uso app:wrapAround (véase más adelante) para crear un bucle.
  • android:focusedByDefault permite a los desarrolladores de aplicaciones para especificar el punto de vista de enfoque predeterminado en la ventana. NO utilice este atributo y app:defaultFocus (véase más adelante) en el mismo FocusArea .

FocusArea también define algunos atributos de personalizar la navegación rotativo. Las áreas de enfoque implícitas no se pueden personalizar con estos atributos.

  1. (Android 11 QPR3, Android 11 coches, Android 12)
    app:defaultFocus se puede utilizar para especificar el ID de una vista descendiente enfocable, que debe centrarse en cuando los empujones de usuario a este FocusArea .
  2. (Android 11 QPR3, Android 11 coches, Android 12)
    app:defaultFocusOverridesHistory se puede configurar para true para hacer la vista especificada por encima de tomar el foco incluso si con la historia para indicar otro punto de vista en este FocusArea se había centrado en.
  3. (Androide 12)
    Uso app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcut y app:nudgeDownShortcut para especificar el ID de una vista descendiente enfocable, que debe centrarse en cuando los empujones de usuario en una dirección dada. Para obtener más información, consulte el contenido de atajos de toque ligero de abajo.

    (Android 11 QPR3, Android 11 coches, obsoleto en Android 12) app:nudgeShortcut y app:nudgeShortcutDirection soportados sólo un acceso directo empujón.

  4. (Android 11 QPR3, Android 11 coches, Android 12)
    Para permitir la rotación de un ciclo en este FocusArea , app:wrapAround se puede ajustar a true . Esto se suele utilizar cuando las vistas se organizan en círculo u óvalo.
  5. (Android 11 QPR3, Android 11 coches, Android 12)
    Para ajustar el relleno de los más destacado en este FocusArea , el uso app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontal y app:highlightPaddingVertical .
  6. (Android 11 QPR3, Android 11 coches, Android 12)
    Para ajustar los límites percibidos de este FocusArea para encontrar un objetivo empujón, el uso app:startBoundOffset , app:endBoundOffset , app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffset y app:verticalBoundOffset .
  7. (Android 11 QPR3, Android 11 coches, Android 12)
    Para especificar explícitamente el ID de un adyacente FocusArea (o zonas) en las direcciones dadas, el uso de app:nudgeLeft , app:nudgeRight , app:nudgeUp , y app:nudgeDown . Use esto cuando la búsqueda geométrica utilizada por defecto no encuentre el objetivo deseado.

Empujar normalmente navega entre FocusAreas. Pero con los atajos de toque ligero, empujando a veces primeros navega dentro de un FocusArea de manera que el usuario puede necesitar para empujar dos veces para navegar a la siguiente FocusArea . Empujar atajos son útiles cuando un FocusArea contiene una larga lista seguido de un flotante botón de acción , como en el siguiente ejemplo:

Atajo de empujar
Atajo Figura 3. Nudge

Sin el atajo de empujar, el usuario tendría que rotar a través de toda la lista para llegar a la FAB.

Enfocar la personalización de los aspectos más destacados

Como se señaló anteriormente, RotaryService se basa en el concepto existente del marco de Android de vista de enfoque. Cuando gira el usuario y empujones, RotaryService mueve el foco alrededor, centrándose una vista y otra unfocusing. En Android, cuando se enfoca una vista, si la vista:

  • ha especificado su propio resaltado de enfoque, Android dibuja el resaltado de enfoque de la vista.
  • no especifica un resaltado de enfoque y el resaltado de enfoque predeterminado no está deshabilitado, Android dibuja el resaltado de enfoque predeterminado para la vista.

Las aplicaciones diseñadas para el tacto generalmente no especifican los aspectos destacados del enfoque adecuados.

El marco de Android proporciona el resaltado de enfoque predeterminado y el OEM puede anularlo. Los desarrolladores de aplicaciones reciben cuando el tema se está utilizando se deriva de Theme.DeviceDefault .

Para una experiencia de usuario consistente, confíe en el resaltado de enfoque predeterminado siempre que sea posible. Si necesita una (por ejemplo, redonda o en forma de píldora) destacado foco en forma personalizada, o si usted está usando un tema que no deriva de Theme.DeviceDefault , utilizar el coche-ui-biblioteca de recursos para especificar su propia destacado foco de cada vista.

Para especificar un resaltado de enfoque personalizado para una vista, cambie el elemento de diseño de fondo o primer plano de la vista a un elemento de diseño que difiera cuando se enfoca la vista. Normalmente, cambiarías el fondo. El siguiente elemento de dibujo, si se utiliza como fondo para una vista cuadrada, produce un resaltado de enfoque redondo:

<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 coches, Android 12) referencias de recursos negrita en el ejemplo anterior a identificar los recursos definidos por el auto-ui-biblioteca. El OEM los anula para que sean coherentes con el resaltado de enfoque predeterminado que especifican. Esto garantiza que el color de resaltado de enfoque, el ancho del trazo, etc. no cambien cuando el usuario navega entre una vista con un resaltado de enfoque personalizado y una vista con el resaltado de enfoque predeterminado. El último elemento es una onda que se usa para tocar. Los valores predeterminados utilizados para los recursos en negrita aparecen de la siguiente manera:

Valores predeterminados para recursos en negrita
Figura 4. Los valores por defecto para los recursos negrita

Además, se requiere un resaltado de enfoque personalizado cuando un botón recibe un color de fondo sólido para llamar la atención del usuario, como en el ejemplo siguiente. Esto puede dificultar la visualización del resaltado de enfoque. En esta situación, especifique un punto culminante de selección personalizado utilizando colores secundarios:

Color de fondo sólido
  • (Android 11 QPR3, Android 11 coches, Android 12)
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • (Androide 12)
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

Por ejemplo:

Centrado, no presionadoEnfocado, presionado
Centrado, no presionado Enfocado, presionado

Desplazamiento giratorio

Si su aplicación utiliza RecyclerView s, se debe utilizar CarUiRecyclerView s en lugar. Esto asegura que su interfaz de usuario es consistente con otros debido a la personalización de un OEM se aplica a todos CarUiRecyclerView s.

Si todos los elementos de su lista se pueden enfocar, no necesita hacer nada más. La navegación giratoria mueve el foco a través de los elementos de la lista y la lista se desplaza para hacer visible el elemento recién enfocado.

(Android 11 QPR3, Android 11 coches, Android 12)
Si hay una combinación de elementos enfocables y desenfocables, o si todos los elementos no se pueden enfocar, puede habilitar el desplazamiento giratorio, lo que permite al usuario usar el controlador giratorio para desplazarse gradualmente por la lista sin omitir elementos desenfocables. Para activar el desplazamiento rotatorio, establezca la app:rotaryScrollEnabled atributo a true .

(Android 11 QPR3, Android 11 coches, Android 12)
Puede activar el desplazamiento rotatorio en cualquier vista desplazable, incluyendo av CarUiRecyclerView , con el setRotaryScrollEnabled() método en el CarUiUtils . Si lo hace, debe:

  • Haga que la vista desplazable sea enfocable para que pueda enfocarse cuando ninguna de sus vistas descendientes enfocables sea visible,
  • Desactivar el resaltado de selección predeterminado en la vista desplazable llamando setDefaultFocusHighlightEnabled(false) de modo que la vista desplazable no parece estar centrado,
  • Asegúrese de que la vista desplazable se centra en sus descendientes antes llamando setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) .
  • Escuchar para MotionEvents con SOURCE_ROTARY_ENCODER y, o bien AXIS_VSCROLL o AXIS_HSCROLL para indicar la distancia para desplazarse y la dirección (a través de la señal).

Cuando el desplazamiento rotatorio está habilitada en un CarUiRecyclerView y gira el usuario a un área donde no hay puntos de vista enfocable están presentes, la barra de desplazamiento cambia de gris a azul, como para indicar la barra de desplazamiento se concentra. Puede implementar un efecto similar si lo desea.

Los MotionEvents son los mismos que los generados por una rueda de desplazamiento en un mouse, excepto por la fuente.

Modo de manipulación directa

Normalmente, los empujones y la rotación navegan a través de la interfaz de usuario, mientras que las pulsaciones del botón central actúan, aunque no siempre es así. Por ejemplo, si un usuario desea ajustar el volumen de la alarma, puede usar el controlador giratorio para navegar hasta el control deslizante de volumen, presionar el botón central, girar el controlador para ajustar el volumen de la alarma y luego presionar el botón Atrás para volver a la navegación. . Esto se conoce como modo de manipulación directa (DM). En este modo, el controlador giratorio se utiliza para interactuar con la vista directamente en lugar de navegar.

Implemente DM de una de dos formas. Si sólo necesita rotación de la manija y la vista que desea manipular responde a ACTION_SCROLL_FORWARD y ACTION_SCROLL_BACKWARD AccessibilityEvent s apropiada, utilice el mecanismo simple. De lo contrario, utilice el mecanismo avanzado.

El mecanismo simple es la única opción en las ventanas del sistema; las aplicaciones pueden utilizar cualquiera de los dos mecanismos.

Mecanismo simple

(Android 11 QPR3, Android 11 coches, Android 12)
Su aplicación debe llamar DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) . RotaryService reconoce cuando el usuario está en el modo de MS y entra en el modo DM cuando el usuario presiona el botón central mientras que un punto de vista se centró. Cuando está en modo de MS, rotaciones realizan ACTION_SCROLL_FORWARD o ACTION_SCROLL_BACKWARD modo de DM y salidas cuando el usuario presiona el botón Atrás. El mecanismo simple alterna el estado seleccionado de la vista al entrar y salir del modo DM.

Para proporcionar una señal visual de que el usuario está en modo DM, haga que su vista parezca diferente cuando se seleccione. Por ejemplo, cambiar el fondo cuando android:state_selected es true .

Mecanismo avanzado

La aplicación determina cuando RotaryService entra y sale del modo de marcos alemanes. Para una experiencia de usuario consistente, presionar el botón central con una vista de DM enfocada debe ingresar al modo DM y el botón Atrás debe salir del modo DM. Si no se utilizan el botón central y / o empujar, pueden ser formas alternativas de salir del modo DM. Para aplicaciones como Maps, se puede usar un botón para representar DM para ingresar al modo DM.

Para admitir el modo DM avanzado, una vista:

  1. (Android 11 QPR3, Android 11 coches, Android 12) deben escuchar para una KEYCODE_DPAD_CENTER evento para entrar en el modo de MS y espere a la KEYCODE_BACK evento para salir del modo de DM, llamando DirectManipulationHelper.enableDirectManipulationMode() en cada caso. Para escuchar estos eventos, realice una de las siguientes acciones:
    • Dar de alta OnKeyListener .
    • o,
    • Extender la vista y luego anular su dispatchKeyEvent() método.
  2. DEBE escuchar los eventos de toque ligero ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT o KEYCODE_DPAD_RIGHT ) si la vista debe manejar empujones.
  3. Debe escuchar a MotionEvent s y obtener recuento de rotación en AXIS_SCROLL si la vista quiere rotación de la manija. Hay varias formas de hacer esto:
    1. Dar de alta OnGenericMotionListener .
    2. Extender la vista y anular su dispatchTouchEvent() método.
  4. Para evitar quedarse atascado en el modo DM, DEBE salir del modo DM cuando el Fragmento o la Actividad a la que pertenece la vista no es interactivo.
  5. DEBE proporcionar una pista visual para indicar que la vista está en modo DM.

A continuación se proporciona una muestra de una vista personalizada que usa el modo DM para desplazarse 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(); }

Más ejemplos se pueden encontrar en el RotaryPlayground proyecto.

ActivityView

Al usar un ActivityView:

  • El ActivityView no debe ser enfocable.
  • (Android 11 QPR3, Android 11 coches, obsoleto en Android 11)
    El contenido de la ActivityView debe contener un FocusParkingView como la primera vista enfocable, y su app:shouldRestoreFocus atributo debe ser false .
  • El contenido de la ActivityView no deben tener ningún android:focusByDefault vistas.

Para el usuario, ActivityViews no debería tener ningún efecto en la navegación, excepto que las áreas de enfoque no pueden abarcar ActivityViews. En otras palabras, no se puede tener una única área de enfoque que tiene en su interior el contenido y fuera de una ActivityView . Si no se agrega ningún FocusAreas a su ActivityView , la raíz de la jerarquía de la vista en el ActivityView se considera un área de enfoque implícito.

Botones que funcionan cuando se mantienen presionados

La mayoría de los botones provocan alguna acción cuando se hace clic en ellos. Algunos botones funcionan cuando se mantienen presionados. Por ejemplo, los botones de avance rápido y retroceso suelen funcionar cuando se mantienen pulsados. Para hacer este tipo de botones de soporte giratorio, escuchan 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 toma una acción (tal como el rebobinado) y los horarios de sí mismo para ser ejecutado después de un retardo.

Modo táctil

Los usuarios pueden usar un controlador giratorio para interactuar con la unidad principal en un automóvil de dos formas, ya sea usando el controlador giratorio o tocando la pantalla. Al usar el controlador giratorio, se resaltará una de las vistas enfocables. Al tocar la pantalla, no aparece ningún resaltado de enfoque. El usuario puede cambiar entre estos modos de entrada en cualquier momento:

  • Giratorio → toque. Cuando el usuario toca la pantalla, el resaltado de enfoque desaparece.
  • Toque → giratorio. Cuando el usuario empuja, gira o presiona el botón central, aparece el resaltado de enfoque.

Los botones Atrás e Inicio no tienen ningún efecto sobre el modo de entrada.

Piggybacks giratorios en concepto existente de Android de modo táctil . Puede utilizar View.isInTouchMode() para determinar el modo de entrada del usuario está utilizando. Puede utilizar OnTouchModeChangeListener para escuchar los cambios. Si bien esto se puede usar para personalizar su interfaz de usuario para el modo de entrada actual, evite cambios importantes, ya que pueden ser desconcertantes.

Solución de problemas

En una aplicación diseñada para el tacto, no es raro tener vistas enfocables anidadas. Por ejemplo, puede haber un FrameLayout alrededor de un ImageButton , ambos de los cuales son enfocable. Esto no daña el tacto, pero puede resultar en una mala experiencia de usuario para el dispositivo giratorio porque el usuario debe girar el controlador dos veces para pasar a la siguiente vista interactiva. Para una buena experiencia de usuario, Google recomienda que haga que la vista exterior o la vista interior sean enfocables, pero no ambas.

Si un botón o interruptor pierde el enfoque cuando se presiona a través del controlador giratorio, se puede aplicar una de estas condiciones:

  • El botón o interruptor se desactiva (breve o indefinidamente) debido a que se presiona el botón. En cualquier caso, hay dos formas de abordar esto:
    • Deje el android:enabled Estado como true y utilizar un estado personalizado para mostrar en gris el botón o el interruptor como se describe en Estado personalizado .
    • Use un recipiente para rodear el botón o interruptor y hacer que el recipiente se pueda enfocar en lugar del botón o interruptor. (El oyente de clics debe estar en el contenedor).
  • El botón o interruptor está siendo reemplazado. Por ejemplo, la acción que se realiza cuando se presiona el botón o se activa el interruptor puede activar una actualización de las acciones disponibles, lo que hace que los botones nuevos reemplacen los botones existentes. Hay dos formas de abordar esto:
    • En lugar de crear un nuevo botón o interruptor, configure el icono y / o el texto del botón o interruptor existente.
    • Como arriba, agregue un contenedor enfocable alrededor del botón o interruptor.

Patio de recreo giratorio

RotaryPlayground es una aplicación de referencia para rotatorio. Úselo para aprender a integrar las diversas funciones rotativas en su aplicación. RotaryPlayground está incluido en emulador y Seahawk construye.

  • RotaryPlayground repositorio: packages/apps/Car/tests/RotaryPlayground/
  • Versiones: Android 11 QPR3, Android 11 Car y Android 12

Los RotaryPlayground aplicación muestra las siguientes fichas de la izquierda:

  • Cartas. Pruebe la navegación alrededor de las áreas de enfoque, omitiendo los elementos que no se pueden enfocar y la entrada de texto.
  • Manipulación directa. Pruebe los widgets que admiten el modo de manipulación directa simple y avanzado. Esta pestaña es específicamente para la manipulación directa dentro de la ventana de la aplicación.
  • Manipulación de la interfaz de usuario del sistema. Pruebe los widgets que admiten la manipulación directa en las ventanas del sistema donde solo se admite el modo de manipulación directa simple.
  • Red. Pruebe la navegación giratoria con patrón z con desplazamiento.
  • Notificación. Pruebe la entrada y salida de las notificaciones de heads-up.
  • Desplazarse. Pruebe el desplazamiento a través de una combinación de contenido enfocable y desenfocado.
  • WebView. Prueba de navegación a través de enlaces en una WebView .
  • Costumbre FocusArea . Prueba FocusArea personalización:
    • Envolver alrededor.
    • android:focusedByDefault y app:defaultFocus
    • .
    • Objetivos de empujón explícitos.
    • Empujar atajos.
    • FocusArea sin vistas enfocable.