Разработка приложений

Следующий материал предназначен для разработчиков приложений.

Чтобы сделать поддержку вашего приложения ротационной, вы ДОЛЖНЫ:

  1. Поместите FocusParkingView в соответствующей компоновке деятельности.
  2. Убедитесь, что виды могут быть (или нет) фокусируемыми.
  3. Используйте FocusArea s , чтобы обернуть вокруг все фокусируемые виды, кроме FocusParkingView .

Каждая из этих задач подробно описана ниже после того, как вы настроите свою среду для разработки приложений с ротационной поддержкой.

Настроить поворотный контроллер

Прежде чем вы сможете приступить к разработке приложений с вращающимся механизмом, вам понадобится либо вращающийся контроллер, либо дублер. У вас есть варианты, описанные ниже.

Эмулятор

source build/envsetup.sh && lunch car_x86_64-userdebug
m -j
emulator -wipe-data -no-snapshot -writable-system

Вы можете также использовать aosp_car_x86_64-userdebug .

Чтобы получить доступ к эмулируемому поворотному контроллеру:

  1. Нажмите на три точки внизу панели инструментов:

    Эмулированный поворотный контроллер доступа
    Рисунок 1. Доступ к эмулировать поворотный контроллер
  2. Выберите автомобиль роторным в расширенном окне элементов управления:

    Выбрать автомобиль поворотный
    Рисунок 2. Выбор автомобиля поворотный

USB-клавиатура

  • Подключите USB-клавиатуру к Seahawk (в некоторых случаях это может помешать отображению экранной клавиатуры).
  • Используйте userdebug или eng сборки.
  • Включение ключа фильтрации событий:
    adb shell settings put secure android.car.ROTARY_KEY_EVENT_FILTER 1
    
  • См. Таблицу ниже, чтобы найти соответствующий ключ для каждого действия:
    Ключ Вращательное действие
    Q Вращаться против часовой стрелки
    E Повернуть по часовой стрелке
    А Сдвинуть влево
    D Сдвинуть вправо
    W Подтолкнуть
    S Подтолкнуть вниз
    F или запятая Центральная кнопка
    R или Esc Кнопка назад

Команды ADB

Вы можете использовать car_service команду , чтобы ввести роторные события ввода. Эти команды можно запускать на Seahawk или эмуляторе.

команды car_service Поворотный ввод
adb shell cmd car_service inject-rotary Вращаться против часовой стрелки
adb shell cmd car_service inject-rotary -c true Повернуть по часовой стрелке
adb shell cmd car_service inject-rotary -dt 100 50 Повернуть против часовой стрелки несколько раз (100 мс назад и 50 мс назад)
adb shell cmd car_service inject-key 282 Сдвинуть влево
adb shell cmd car_service inject-key 283 Сдвинуть вправо
adb shell cmd car_service inject-key 280 Подтолкнуть
adb shell cmd car_service inject-key 281 Подтолкнуть вниз
adb shell cmd car_service inject-key 23 Нажатие центральной кнопки
adb shell input keyevent inject-key 4 Нажатие кнопки "Назад"

OEM поворотный контроллер

Когда оборудование вашего поворотного контроллера установлено и работает, это наиболее реалистичный вариант. Это особенно полезно для тестирования быстрого вращения.

FocusParkingView

FocusParkingView представляет собой прозрачный вид в библиотеке автомобиля UI (автомобиль-UI-библиотека) . RotaryService использует его для поддержки поворотного контроллера навигации. FocusParkingView должен быть первым фокусируемый вид в макете. Он должен быть размещен за пределами всех FocusArea s. Каждое окно должно иметь один FocusParkingView . Если вы уже используете автомобиль-UI-библиотека базовый макет, который содержит FocusParkingView , вам не нужно добавить еще один FocusParkingView . Ниже показан пример FocusParkingView в 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>

Вот причины , вам нужен FocusParkingView :

  1. Android не сбрасывает фокус автоматически, когда фокус устанавливается в другом окне. Если вы попытаетесь сбросить фокус в предыдущем окне, Android перефокусирует представление в этом окне, в результате чего два окна будут сфокусированы одновременно. Добавление FocusParkingView к каждому окну может исправить эту проблему. Это представление является прозрачным, и его выделение фокуса по умолчанию отключено, поэтому оно невидимо для пользователя независимо от того, сфокусирован он или нет. Он может принимать фокус , так что RotaryService может оставить фокус на нем , чтобы удалить фокус блик.
  2. Если есть только один FocusArea в текущем окне, вращая регулятор в FocusArea вызывает RotaryService , чтобы переместить фокус с точки зрения на право представления слева (и наоборот). Добавление этого представления в каждое окно может решить проблему. Когда RotaryService определяет целевой фокус является FocusParkingView , он может определить , укручение может произойти в этот момент он избегает наматывается вокруг, не перемещая фокус.
  3. Когда запуски роторного управления приложением, Android фокусирует первый фокусируемых вида, который всегда FocusParkingView . FocusParkingView определяет вид оптимальный , чтобы сосредоточиться на , а затем применяет фокус.

Фокусируемые виды

RotaryService основывается на Android фреймворки существующей концепции зрения фокуса, датируемый , когда телефоны были физические клавиатуры и D-колодка. Существующий android:nextFocusForward атрибут для переориентированы роторный (см FocusArea настройки ), но android:nextFocusLeft , android:nextFocusRight , android:nextFocusUp и android:nextFocusDown нет.

RotaryService фокусируется только на представлениях, которые фокусирование. Некоторые виды, такие как Button с, как правило , фокусирования. Другие, такие как TextView s и ViewGroup s, как правило , не являются. Интерактивные представления автоматически настраиваются, а представления автоматически активируются, если у них есть прослушиватель щелчков. Если эта автоматическая логика приводит к желаемой фокусируемости, вам не нужно явно устанавливать фокусируемость представления. Если автоматическая логика не приводит к желаемой фокусируемости установите android:focusable атрибут true или false , или программно установить фокусируемости отображения вида с View.setFocusable(boolean) . Для RotaryService сосредоточиться на нем, вид должен отвечать следующим требованиям:

  • Фокусируемый
  • Включено
  • Видимый
  • Иметь ненулевые значения для ширины и высоты

Если представление не соответствует всем этим требованиям, например, кнопка с фокусировкой, но отключена, пользователь не может использовать поворотный элемент управления, чтобы сфокусироваться на нем. Если вы хотите сосредоточиться на взгляды инвалидов, рассмотреть возможность использования пользовательского состояния , а не android:state_enabled , чтобы контролировать то, как представляется мнение , не указывая , что Android должен рассмотреть его выключенным. Ваше приложение может сообщить пользователю, почему представление отключено при нажатии. В следующем разделе объясняется, как это сделать.

Пользовательское состояние

Чтобы добавить настраиваемое состояние:

  1. Для добавления пользовательского атрибута к вашему мнению. Например, чтобы добавить state_rotary_enabled пользовательского состояния на CustomView вид класс, используйте:
    <declare-styleable name="CustomView">
        <attr name="state_rotary_enabled" format="boolean" />
    </declare-styleable>
    
  2. Для отслеживания этого состояния, добавьте переменный экземпляр к представлению вместе с методами доступа:
    private boolean mRotaryEnabled;
    public boolean getRotaryEnabled() { return mRotaryEnabled; }
    public void setRotaryEnabled(boolean rotaryEnabled) {
        mRotaryEnabled = rotaryEnabled;
    }
    
  3. Для того, чтобы прочитать значение атрибута при создании вашего мнения:
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    mRotaryEnabled = a.getBoolean(R.styleable.CustomView_state_rotary_enabled);
    
  4. В своем классе вид, переопределить onCreateDrawableState() метод , а затем добавить пользовательское состояние, когда это необходимо. Например:
    @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. Сделайте так, чтобы обработчик кликов вашего представления работал по-разному в зависимости от его состояния. Например, обработчик щелчка не может ничего сделать , или это может выскочить тост , когда mRotaryEnabled является false .
  6. Для того, чтобы кнопки появляются инвалидами, в фоновом режиме Drawable вашего взгляда, в использовании app:state_rotary_enabled вместо android:state_enabled . Если вы уже не имеете его, вам нужно добавить:
    xmlns:app="http://schemas.android.com/apk/res-auto"
    
  7. Если ваш вид отключен в любых компоновок, заменить android:enabled="false" с app:state_rotary_enabled="false" , а затем добавить app пространства имен, как указано выше.
  8. Если точка зрения программно отключена, заменить вызовы на setEnabled() с вызовами setRotaryEnabled() .

Зона фокусировки

Используйте FocusAreas для разделения фокусируемых взглядов на блоки , чтобы сделать навигацию проще и быть совместимым с другими приложениями. Например, если ваше приложение имеет панель инструментов, панель должна быть в отдельном FocusArea от остальной части вашего приложения. Панели вкладок и другие элементы навигации также должны быть отделены от остальной части приложения. Большие списки как правило , должны иметь свои собственные FocusArea . В противном случае пользователи должны прокручивать весь список, чтобы получить доступ к некоторым представлениям.

FocusArea подкласс LinearLayout в машине-UI-библиотеки. Когда эта функция включена, FocusArea нарисует блик , когда один из его потомков будет сфокусирован. Чтобы узнать больше, см Фокус высвечивающейся настройки .

При создании навигационного блока в файле макета, если вы собираетесь использовать LinearLayout в качестве контейнера для этого блока используйте FocusArea вместо этого. В противном случае, заверните блок в FocusArea .

Не гнездятся в FocusArea в другом FocusArea . Это приведет к неопределенному поведению навигации. Убедитесь , что все фокусируемые взгляды вложены в FocusArea .

Пример FocusArea в RotaryPlayground показан ниже:

<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 работает следующим образом :

  1. При работе во вращение и подталкивать действия, RotaryService ищет экземпляры FocusArea в иерархии представлений.
  2. При получении события вращения, RotaryService перемещает фокус на другую точку зрения , которая может принимать фокус в том же FocusArea .
  3. При получении события Сдвинуть, RotaryService перемещения фокуса на другую точку зрения , которая может принимать фокус в другом (обычно соседнем) FocusArea .

Если вы не включаете FocusAreas в макете, вид корня трактуются как неявные зоны фокусировки. Пользователь не может подтолкнуть к навигации в приложении. Вместо этого они будут вращаться во всех фокусируемых представлениях, что может быть адекватным для диалогов.

Настройка FocusArea

Для настройки поворотной навигации можно использовать два стандартных атрибута View:

  • android:nextFocusForward позволяет разработчикам приложений , чтобы указать порядок ротации в фокусной области. Это тот же атрибут, который используется для управления порядком табуляции при навигации с помощью клавиатуры. Не используйте этот атрибут для создания цикла. Вместо этого используйте app:wrapAround (см ниже) , чтобы создать цикл.
  • android:focusedByDefault позволяет разработчикам приложений указать вид фокусировки по умолчанию в окне. Не используйте этот атрибут и app:defaultFocus (смотрите ниже) в том же FocusArea .

FocusArea также определяет некоторые атрибуты для настройки роторной навигации. Неявные области фокусировки не могут быть настроены с помощью этих атрибутов.

  1. (Android 11 QPR3, Android 11 автомобилей, Android 12)
    app:defaultFocus может быть использован для указания идентификатора фокусируемого потомка зрения, которая должна быть сосредоточена на когда пользователь подталкивание к этому FocusArea .
  2. (Android 11 QPR3, Android 11 автомобилей, Android 12)
    app:defaultFocusOverridesHistory может быть установлен true , чтобы сделать вид , указанный выше тейк фокусе , даже если с историей , чтобы указать другую точку зрения в этом FocusArea был в центре внимания.
  3. (Android 12)
    Используйте app:nudgeLeftShortcut , app:nudgeRightShortcut , app:nudgeUpShortcut и app:nudgeDownShortcut указать идентификатор фокусируемого зрения потомка, который должен быть сосредоточен на когда подталкивания пользователя в заданном направлении. Чтобы узнать больше, увидеть содержимое для ярлыков Сдвинуть ниже.

    (Android 11 QPR3, Android 11 автомобилей, осуждается в Android 12) app:nudgeShortcut и app:nudgeShortcutDirection поддерживается только один Сдвинуть ярлык.

  4. (Android 11 QPR3, Android 11 автомобилей, Android 12)
    Чтобы включить вращение , чтобы обернуть вокруг в этом FocusArea , app:wrapAround может быть установлен true . Это чаще всего используется, когда виды расположены по кругу или овалу.
  5. (Android 11 QPR3, Android 11 автомобилей, Android 12)
    Для того, чтобы настроить отступы блика в этом FocusArea , используйте app:highlightPaddingStart , app:highlightPaddingEnd , app:highlightPaddingTop , app:highlightPaddingBottom , app:highlightPaddingHorizontal и app:highlightPaddingVertical .
  6. (Android 11 QPR3, Android 11 автомобилей, Android 12)
    Для регулировки воспринимаемых границ этого FocusArea найти целевое подталкивание, использовать app:startBoundOffset , app:endBoundOffset , app:topBoundOffset , app:bottomBoundOffset , app:horizontalBoundOffset и app:verticalBoundOffset .
  7. (Android 11 QPR3, Android 11 автомобилей, Android 12)
    Чтобы явно указать идентификатор соседнего FocusArea (или областей) в заданных направлениях, используйте app:nudgeLeft , app:nudgeRight , app:nudgeUp , и app:nudgeDown . Используйте это, когда используемый по умолчанию геометрический поиск не находит желаемой цели.

Смещение обычно перемещается между FocusAreas. Но с ярлыками Сдвинуть, подталкивая иногда первые Переходит в FocusArea , так что пользователь может потребоваться дважды подталкивать , чтобы перейти к следующему FocusArea . Сдвинуть ярлыки полезны , когда FocusArea содержит длинный список с последующим плавающей кнопкой действий , как в примере ниже:

Ярлык Nudge
Рисунок 3. Сдвинуть ярлык

Без ярлыка подталкивания пользователю пришлось бы прокручивать весь список, чтобы добраться до FAB.

Настройка выделения фокуса

Как было отмечено выше, RotaryService опирается на существующем андроид фреймворка концепции зрения фокуса. При вращении пользователя и подталкивания, RotaryService перемещает фокус вокруг, сосредоточившись один вид и unfocusing другой. В Android, когда представление сфокусировано, если представление:

  • указал свое собственное выделение фокуса, Android рисует выделение фокуса представления.
  • не указывает выделение фокуса, и выделение фокуса по умолчанию не отключено, Android рисует выделение фокуса по умолчанию для представления.

В приложениях, разработанных для сенсорного управления, обычно не указываются соответствующие основные моменты.

Подсветка фокуса по умолчанию предоставляется платформой Android и может быть отменена OEM. Разработчики приложений получают его , когда тему , они используют происходят от Theme.DeviceDefault .

Для единообразия взаимодействия с пользователем по возможности полагайтесь на выделение фокуса по умолчанию. Если вам нужен заказной формы (например, круглой или таблетки-форме) выделить фокус, или если вы используете тему не производный от Theme.DeviceDefault , использовать автомобиль-UI-библиотека ресурсов , чтобы указать свой собственный фокус выделить для каждый вид.

Чтобы указать настраиваемое выделение фокуса для представления, измените фон или передний план, доступный для рисования, на доступный для рисования, который отличается, когда вид сфокусирован. Обычно вы меняете фон. Следующий объект, который можно рисовать, если он используется в качестве фона для квадратного вида, создает круглую подсветку фокуса:

<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 автомобилей, Android 12) Жирные ссылки ресурсов в образце выше определить ресурсы , определенные автопоезда Ui-библиотеки. OEM переопределяет их, чтобы они соответствовали установленному по умолчанию выделению фокуса. Это гарантирует, что цвет выделения фокуса, ширина штриха и т. Д. Не изменятся при переходе пользователя между представлением с настраиваемым выделением фокуса и представлением с выделением фокуса по умолчанию. Последний элемент - это рябь, используемая для прикосновения. Значения по умолчанию, используемые для ресурсов, выделенных жирным шрифтом, выглядят следующим образом:

Значения по умолчанию для ресурсов, выделенных жирным шрифтом
Рисунок 4. Значение по умолчанию для смелых ресурсов

Кроме того, настраиваемая подсветка фокуса вызывается, когда кнопке дается сплошной цвет фона, чтобы привлечь внимание пользователя, как в примере ниже. Это может затруднить отображение выделения в фокусе. В этой ситуации, указать пользовательский фокус блик используя вторичные цвета:

Сплошной цвет фона
  • (Android 11 QPR3, Android 11 автомобилей, 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

Например:

Сфокусировано, не нажимаетсяСосредоточенный, нажатый
Сфокусированный, не нажатый Сосредоточенный, нажатый

Поворотная прокрутка

Если ваше приложение использует RecyclerView s, вы должны использовать CarUiRecyclerView с вместо. Это гарантирует , что ваш пользовательский интерфейс в соответствии с другими , потому что настройка ПВТ распространяется на все CarUiRecyclerView s.

Если все элементы в вашем списке доступны для фокусировки, больше ничего делать не нужно. Поворотная навигация перемещает фокус по элементам в списке, и список прокручивается, чтобы сделать новый элемент, сфокусированный на фокусе, видимым.

(Android 11 QPR3, Android 11 автомобилей, Android 12)
Если есть сочетание фокусируемых и нефокусируемых элементов или если все элементы нефокусируемые, вы можете включить поворотную прокрутку, которая позволяет пользователю использовать поворотный контроллер для постепенной прокрутки списка, не пропуская нефокусируемые элементы. Чтобы включить роторные прокрутки, установите app:rotaryScrollEnabled атрибут true .

(Android 11 QPR3, Android 11 автомобилей, Android 12)
Можно включить роторный прокрутку в любом прокруткой зрения, в том числе ав CarUiRecyclerView , с setRotaryScrollEnabled() метода в CarUiUtils . Если вы это сделаете, вам необходимо:

  • Сделайте прокручиваемое представление фокусируемым, чтобы на нем можно было сфокусироваться, когда ни одно из его фокусируемых дочерних представлений не видно,
  • Отключение фокуса по умолчанию выделите на на прокрутке представления вызвав setDefaultFocusHighlightEnabled(false) , так что прокручивать представление не по всей видимости, сосредоточенному,
  • Убедитесь в том, что прокручивать вид ориентирован на перед своими потомками, вызвав setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS) .
  • Прислушайтесь MotionEvents с SOURCE_ROTARY_ENCODER и либо AXIS_VSCROLL или AXIS_HSCROLL , чтобы указать расстояние до прокрутки и направление (через знак).

Когда роторный прокрутка включена на CarUiRecyclerView и вращается пользователя в область , где нет фокусируемые мнения не присутствуют, то полоса прокрутки изменяется от серого до синего, как будто указывают на полосе прокрутки сосредоточенным. Вы можете реализовать аналогичный эффект, если хотите.

События MotionEvents такие же, как и события, генерируемые колесом прокрутки мыши, за исключением источника.

Режим прямого манипулирования

Обычно смещение и вращение перемещаются по пользовательскому интерфейсу, в то время как нажатие центральной кнопки приводит к действию, хотя это не всегда так. Например, если пользователь хочет отрегулировать громкость будильника, он может использовать поворотный контроллер для перехода к ползунку громкости, нажать центральную кнопку, повернуть контроллер, чтобы отрегулировать громкость будильника, а затем нажать кнопку «Назад», чтобы вернуться к навигации. . Это называется режимом прямого манипулирования (DM). В этом режиме поворотный контроллер используется для непосредственного взаимодействия с обзором, а не для навигации.

Реализуйте DM одним из двух способов. Если вам нужно только вращение ручки и вид вы хотите управлять реагирует на ACTION_SCROLL_FORWARD и ACTION_SCROLL_BACKWARD AccessibilityEvent s соответственно, использовать простой механизм. В противном случае, используйте усовершенствованный механизм.

Простой механизм - единственный вариант в системных окнах; приложения могут использовать любой механизм.

Простой механизм

(Android 11 QPR3, Android 11 автомобилей, Android 12)
Ваше приложение должно назвать DirectManipulationHelper.setSupportsRotateDirectly(View view, boolean enable) . RotaryService распознает , когда пользователь находится в режиме DM и переходит в режим DM , когда пользователь нажимает на центральную кнопку , пока вид сфокусирован. При работе в режиме DM, севообороты выполнять ACTION_SCROLL_FORWARD или ACTION_SCROLL_BACKWARD режим DM и выходит из когда пользователь нажимает на кнопку Назад. Простой механизм переключает выбранное состояние обзора при входе и выходе из режима DM.

Чтобы обеспечить визуальную подсказку о том, что пользователь находится в режиме DM, измените вид при выборе. Например, изменить фон , когда android:state_selected это true .

Продвинутый механизм

Приложение определяет , когда RotaryService входит и выходит из режима DM. Для единообразного взаимодействия с пользователем нажатие центральной кнопки с сфокусированным видом DM должно переходить в режим DM, а кнопка «Назад» должна выходить из режима DM. Если центральная кнопка и / или подталкивание не используются, они могут быть альтернативными способами выхода из режима DM. Для таких приложений, как Карты, кнопка, представляющая DM, может использоваться для входа в режим DM.

Для поддержки расширенного режима DM вид:

  1. (Android 11 QPR3, Android 11 автомобилей, Android 12) ДОЛЖНЫ прослушайте KEYCODE_DPAD_CENTER события , чтобы войти в режим DM и слушать для KEYCODE_BACK события в режим выхода DM, вызывая DirectManipulationHelper.enableDirectManipulationMode() в каждом конкретном случае. Чтобы прослушать эти события, выполните одно из следующих действий:
    • Зарегистрировать OnKeyListener .
    • или,
    • Продлить вид , а затем переопределить его dispatchKeyEvent() метод.
  2. Следует слушать Сдвинуть события ( KEYCODE_DPAD_UP , KEYCODE_DPAD_DOWN , KEYCODE_DPAD_LEFT или KEYCODE_DPAD_RIGHT ) , если вид должен обрабатывать подталкивание.
  3. Следует слушать MotionEvent s и получить счет вращения в AXIS_SCROLL , если представление хочет вращения ручки. Есть несколько способов сделать это:
    1. Зарегистрировать OnGenericMotionListener .
    2. Продлить вид и переопределить его dispatchTouchEvent() метод.
  4. Чтобы избежать застревания в режиме DM, ДОЛЖЕН выйти из режима DM, когда фрагмент или действие, к которому принадлежит представление, не является интерактивным.
  5. СЛЕДУЕТ предоставлять визуальную подсказку, чтобы указать, что представление находится в режиме DM.

Ниже приведен образец пользовательского представления, в котором для панорамирования и масштабирования карты используется режим DM:

/** 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(); }

Другие примеры можно найти в RotaryPlayground проекте.

ActivityView

При использовании ActivityView:

  • ActivityView не должно быть фокусирования.
  • (Android 11 QPR3, Android 11 автомобилей, осуждается в Android 11)
    Содержимое ActivityView должны содержать FocusParkingView в качестве первого фокусируемого зрения, и его app:shouldRestoreFocus атрибут должен быть false .
  • Содержимое ActivityView не должны иметь android:focusByDefault взглядов.

Для пользователя ActivityView не должны влиять на навигацию, за исключением того, что области фокусировки не могут охватывать ActivityView. Другими словами, вы не можете иметь одну зону фокусировки , которая имеет внутри содержимого и за пределами ActivityView . Если вы не добавляйте FocusAreas к вашему ActivityView , корень иерархии представлений в ActivityView считается неявной зоной фокусировки.

Кнопки, которые работают при удерживании

Большинство кнопок при нажатии вызывают какое-либо действие. Вместо этого некоторые кнопки работают, когда они удерживаются нажатыми. Например, кнопки «Быстрая перемотка вперед» и «Перемотка назад» обычно работают, когда они удерживаются нажатыми. Для того, чтобы такие кнопки поддерживают поворотные, слушать KEYCODE_DPAD_CENTER KeyEvents следующим образом :

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;
});

В котором mRunnable принимает действие (например, перематывать) и графики само по себе будет работать после задержки.

Сенсорный режим

Пользователи могут использовать поворотный контроллер для взаимодействия с головным устройством в автомобиле двумя способами: либо с помощью поворотного контроллера, либо путем прикосновения к экрану. При использовании поворотного контроллера будет выделен один из фокусируемых видов. При прикосновении к экрану выделение фокуса не появляется. Пользователь может переключаться между этими режимами ввода в любое время:

  • Поворотный → коснитесь. Когда пользователь касается экрана, выделение фокуса исчезает.
  • Нажмите → поворотный. Когда пользователь подталкивает, вращает или нажимает центральную кнопку, появляется выделение фокуса.

Кнопки «Назад» и «Домой» не влияют на режим ввода.

Вращающиеся на существующем накладывает концепции Android, в сенсорном режиме . Вы можете использовать View.isInTouchMode() , чтобы определить , какой режим ввода пользователь использует. Вы можете использовать OnTouchModeChangeListener для прослушивания изменений. Хотя это можно использовать для настройки вашего пользовательского интерфейса для текущего режима ввода, избегайте каких-либо серьезных изменений, поскольку они могут сбить с толку.

Исправление проблем

В приложении, предназначенном для сенсорного управления, нередко есть вложенные фокусируемые представления. Например, там может быть FrameLayout вокруг ImageButton , оба из которых являются фокусируемыми. Это не наносит вреда касанию, но может привести к неудовлетворительному взаимодействию с вращением, поскольку пользователь должен дважды повернуть контроллер, чтобы перейти к следующему интерактивному представлению. Для удобства пользователей Google рекомендует сделать фокусируемым либо внешний вид, либо внутренний вид, но не оба сразу.

Если кнопка или переключатель теряет фокус при нажатии на поворотный контроллер, может применяться одно из следующих условий:

  • Кнопка или переключатель отключены (на короткое время или на неопределенный срок) из-за нажатия кнопки. В любом случае есть два способа решить эту проблему:
    • Оставьте android:enabled состояние как true и использовать пользовательское состояние , чтобы серый цвет кнопку или переключатель , как описано в пользовательском государстве .
    • Используйте контейнер, чтобы окружить кнопку или переключатель и сделать контейнер доступным для фокусировки вместо кнопки или переключателя. (Слушатель кликов должен находиться в контейнере.)
  • Замена кнопки или переключателя. Например, действие, выполняемое при нажатии кнопки или переключении переключателя, может запускать обновление доступных действий, в результате чего новые кнопки заменяют существующие. Есть два способа решить эту проблему:
    • Вместо создания новой кнопки или переключателя установите значок и / или текст существующей кнопки или переключателя.
    • Как и выше, добавьте фокусируемый контейнер вокруг кнопки или переключателя.

Ротари

RotaryPlayground является ссылкой приложение для роторный. Используйте его, чтобы узнать, как интегрировать различные поворотные функции в ваше приложение. RotaryPlayground включен в эмуляторе и Seahawk строит.

  • RotaryPlayground хранилище: packages/apps/Car/tests/RotaryPlayground/
  • Версии: Android 11 QPR3, Android 11 Car и Android 12.

В RotaryPlayground приложение показывает следующие вкладки слева:

  • Карты. Протестируйте навигацию по областям фокусировки, пропуская нефокусируемые элементы и ввод текста.
  • Прямое манипулирование. Тестовые виджеты, поддерживающие простой и расширенный режим прямого управления. Эта вкладка предназначена специально для прямого управления в окне приложения.
  • Манипуляции с пользовательским интерфейсом Sys. Тестовые виджеты, поддерживающие прямое управление в системных окнах, где поддерживается только простой режим прямого управления.
  • Сетка. Протестируйте поворотную навигацию по z-шаблону с прокруткой.
  • Уведомление. Протестируйте включение и отключение уведомлений.
  • Прокрутите. Протестируйте прокрутку как настраиваемого, так и нефокусируемого содержимого.
  • WebView. Тест навигации по ссылкам в WebView .
  • Пользовательское FocusArea . Тест FocusArea настройки:
    • Обертывание.
    • android:focusedByDefault и app:defaultFocus
    • .
    • Явные цели подталкивания.
    • Сдвигайте ярлыки.
    • FocusArea без каких - либо форматируемых взглядов.