Обзор входных событий

Попробуйте способ создания композиций.
Jetpack Compose — это рекомендуемый набор инструментов для создания пользовательского интерфейса для Android. Узнайте, как использовать сенсорный ввод и другие средства ввода в Compose.

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

В различных классах View, которые вы будете использовать для построения макета, вы можете заметить несколько открытых методов обратного вызова, которые кажутся полезными для обработки событий пользовательского интерфейса. Эти методы вызываются фреймворком Android, когда происходит соответствующее действие с данным объектом. Например, при касании View (например, кнопки) вызывается метод onTouchEvent() для этого объекта. Однако, чтобы перехватить это, необходимо расширить класс и переопределить соответствующий метод. Тем не менее, расширение каждого объекта View для обработки такого события было бы непрактичным. Именно поэтому класс View также содержит набор вложенных интерфейсов с методами обратного вызова, которые гораздо проще определить. Эти интерфейсы, называемые обработчиками событий , — ваш ключ к перехвату взаимодействия пользователя с вашим пользовательским интерфейсом.

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

слушатели мероприятия

Обработчик событий — это интерфейс в классе View , содержащий единственный метод обратного вызова. Эти методы будут вызываться фреймворком Android, когда View, к которому зарегистрирован обработчик событий, активируется в результате взаимодействия пользователя с элементом пользовательского интерфейса.

В интерфейсы обработчиков событий включены следующие методы обратного вызова:

onClick()
Из View.OnClickListener . Этот метод вызывается, когда пользователь либо касается элемента (в сенсорном режиме), либо фокусируется на элементе с помощью навигационных клавиш или трекбола и нажимает соответствующую клавишу «Enter» или нажимает на трекбол.
onLongClick()
Из View.OnLongClickListener . Этот метод вызывается, когда пользователь либо касается и удерживает элемент (в сенсорном режиме), либо фокусируется на элементе с помощью навигационных клавиш или трекбола и нажимает и удерживает соответствующую клавишу «Enter», либо нажимает и удерживает трекбол (в течение одной секунды).
onFocusChange()
Этот метод вызывается в View.OnFocusChangeListener , когда пользователь переходит на элемент или сходит с него, используя клавиши навигации или трекбол.
onKey()
Этот метод вызывается в View.OnKeyListener , когда пользователь фокусируется на элементе и нажимает или отпускает аппаратную клавишу на устройстве.
onTouch()
Из View.OnTouchListener . Этот метод вызывается, когда пользователь выполняет действие, квалифицируемое как событие касания, включая нажатие, отпускание или любой жест перемещения по экрану (в пределах границ элемента).
onCreateContextMenu()
Из View.OnCreateContextMenuListener . Этот метод вызывается при создании контекстного меню (в результате длительного "нажатия"). См. обсуждение контекстных меню в руководстве разработчика по меню .

Эти методы являются единственными обитателями соответствующих интерфейсов. Чтобы определить один из этих методов и обрабатывать ваши события, реализуйте вложенный интерфейс в вашей Activity или определите его как анонимный класс. Затем передайте экземпляр вашей реализации соответствующему методу View.set...Listener() . (Например, вызовите setOnClickListener() и передайте ему вашу реализацию OnClickListener .)

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

Котлин

protected void onCreate(savedValues: Bundle) {
    ...
    val button: Button = findViewById(R.id.corky)
    // Register the onClick listener with the implementation above
    button.setOnClickListener { view ->
        // do something when the button is clicked
    }
    ...
}

Java

// Create an anonymous implementation of OnClickListener
private OnClickListener corkyListener = new OnClickListener() {
    public void onClick(View v) {
      // do something when the button is clicked
    }
};

protected void onCreate(Bundle savedValues) {
    ...
    // Capture our button from layout
    Button button = (Button)findViewById(R.id.corky);
    // Register the onClick listener with the implementation above
    button.setOnClickListener(corkyListener);
    ...
}

Возможно, вам также будет удобнее реализовать OnClickListener как часть вашей Activity. Это позволит избежать дополнительной загрузки классов и выделения памяти для объектов. Например:

Котлин

class ExampleActivity : Activity(), OnClickListener {
  
    protected fun onCreate(savedValues: Bundle) {
        val button: Button = findViewById(R.id.corky)
        button.setOnClickListener(this)
    }

    // Implement the OnClickListener callback
    fun onClick(v: View) {
        // do something when the button is clicked
    }
}

Java

public class ExampleActivity extends Activity implements OnClickListener {
    protected void onCreate(Bundle savedValues) {
        ...
        Button button = (Button)findViewById(R.id.corky);
        button.setOnClickListener(this);
    }

    // Implement the OnClickListener callback
    public void onClick(View v) {
      // do something when the button is clicked
    }
    ...
}

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

  • onLongClick() - Эта функция возвращает логическое значение, указывающее, обработано ли событие и не следует ли передавать его дальше. То есть, верните true , если событие обработано и следует остановиться; верните false , если событие не обработано и/или следует передать его другим обработчикам события onclick.
  • onKey() - Эта функция возвращает логическое значение, указывающее, обработано ли событие и не следует ли его передавать дальше. То есть, верните true , если событие обработано и следует остановиться; верните false , если событие не обработано и/или должно передаваться другим обработчикам события onKey.
  • onTouch() — эта функция возвращает логическое значение, указывающее, обрабатывает ли ваш слушатель это событие. Важно отметить, что это событие может иметь несколько действий, следующих друг за другом. Таким образом, если вы возвращаете false при получении события нажатия, вы указываете, что не обработали событие и не заинтересованы в последующих действиях, связанных с этим событием. Следовательно, вас не будут вызывать для каких-либо других действий в рамках события, таких как жест пальцем или последующее событие нажатия.

Помните, что события нажатия аппаратных клавиш всегда доставляются в представление, находящееся в данный момент в фокусе. Они отправляются, начиная с вершины иерархии представлений, и далее вниз, пока не достигнут соответствующего пункта назначения. Если ваше представление (или дочернее представление) в данный момент находится в фокусе, вы можете увидеть, как событие передается через метод dispatchKeyEvent() . В качестве альтернативы перехвату событий нажатия клавиш через ваше представление, вы также можете получать все события внутри вашей активности с помощью onKeyDown() и onKeyUp() .

Кроме того, при разработке текстового ввода для вашего приложения помните, что многие устройства имеют только программные методы ввода. Такие методы не обязательно должны быть основаны на клавишах; некоторые могут использовать голосовой ввод, рукописный ввод и так далее. Даже если метод ввода предоставляет интерфейс, похожий на клавиатуру, он, как правило, не будет запускать события семейства onKeyDown() . Никогда не создавайте пользовательский интерфейс, требующий управления нажатиями определенных клавиш, если только вы не хотите ограничить свое приложение устройствами с аппаратной клавиатурой. В частности, не полагайтесь на эти методы для проверки ввода при нажатии пользователем клавиши Enter; вместо этого используйте действия, такие как IME_ACTION_DONE чтобы сообщить методу ввода, как ваше приложение ожидает отреагировать, чтобы оно могло осмысленно изменить свой пользовательский интерфейс. Избегайте предположений о том, как должен работать программный метод ввода, и просто доверьтесь ему в предоставлении уже отформатированного текста вашему приложению.

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

Обработчики событий

Если вы создаёте пользовательский компонент на основе View, то сможете определить несколько методов обратного вызова, используемых в качестве обработчиков событий по умолчанию. В документе о пользовательских компонентах View вы узнаете о некоторых распространённых методах обратного вызова, используемых для обработки событий, в том числе:

  • onKeyDown(int, KeyEvent) - Вызывается при возникновении нового события нажатия клавиши.
  • onKeyUp(int, KeyEvent) - Вызывается при нажатии клавиши.
  • onTrackballEvent(MotionEvent) - Вызывается при возникновении события движения трекбола.
  • onTouchEvent(MotionEvent) - Вызывается при возникновении события движения на сенсорном экране.
  • onFocusChanged(boolean, int, Rect) - Вызывается при получении или потере фокуса элементом интерфейса.

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

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

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

На устройствах с сенсорным экраном, как только пользователь коснется экрана, устройство перейдет в сенсорный режим. С этого момента фокусироваться смогут только те элементы, для которых isFocusableInTouchMode() имеет значение true, например, виджеты для редактирования текста. Другие элементы, к которым можно прикоснуться, например, кнопки, не будут получать фокус при касании; они просто будут активировать свои обработчики событий при нажатии.

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

Состояние сенсорного режима сохраняется во всей системе (во всех окнах и действиях). Чтобы узнать текущее состояние, можно вызвать isInTouchMode() чтобы проверить, находится ли устройство в данный момент в сенсорном режиме.

Управление фокусом

Фреймворк будет обрабатывать стандартные перемещения фокуса в ответ на ввод пользователя. Это включает в себя изменение фокуса при удалении или скрытии представлений, а также при появлении новых представлений. Представления указывают на свою готовность к получению фокуса с помощью метода isFocusable() . Чтобы изменить возможность получения фокуса для представления, вызовите метод setFocusable() . В сенсорном режиме вы можете запросить разрешение на получение фокуса для представления с помощью isFocusableInTouchMode() . Вы можете изменить это с помощью setFocusableInTouchMode() .

На устройствах под управлением Android 9 (уровень API 28) и выше начальный фокус для действий не назначается автоматически. Вместо этого, при желании, необходимо явно запросить начальный фокус.

Перемещение фокуса основано на алгоритме, который находит ближайшего соседа в заданном направлении. В редких случаях алгоритм по умолчанию может не соответствовать предполагаемому поведению разработчика. В таких ситуациях вы можете явно переопределить следующие XML-атрибуты в файле разметки: nextFocusDown , nextFocusLeft , nextFocusRight и nextFocusUp . Добавьте один из этих атрибутов к представлению, из которого перемещается фокус. Определите значение атрибута как идентификатор представления , которому должен быть передан фокус. Например:

<LinearLayout
    android:orientation="vertical"
    ... >
  <Button android:id="@+id/top"
          android:nextFocusUp="@+id/bottom"
          ... />
  <Button android:id="@+id/bottom"
          android:nextFocusDown="@+id/top"
          ... />
</LinearLayout>

Обычно в такой вертикальной компоновке навигация вверх от первой кнопки никуда бы не привела, как и навигация вниз от второй кнопки. Теперь, когда верхняя кнопка определила нижнюю как nextFocusUp (и наоборот), фокус навигации будет переключаться сверху вниз и снизу вверх.

Если вы хотите объявить View фокусируемым в вашем пользовательском интерфейсе (когда он традиционно не фокусируется), добавьте XML-атрибут android:focusable к View в объявлении макета. Установите значение true . Вы также можете объявить View фокусируемым в сенсорном режиме с помощью android:focusableInTouchMode .

Чтобы запросить фокусировку на определенном представлении (View), вызовите requestFocus() .

Для отслеживания событий фокусировки (получения уведомлений о получении или потере фокуса элементом представления) используйте onFocusChange() , как описано в разделе « Обработчики событий» .