Android studio keyboard events

Клавиатура и аппаратные кнопки

Аппаратные и клавиатурные клавиши

Обработка аппаратных клавиш и клавиатуры имеет следующие методы

  • onKeyDown() — вызывается при нажатии любой аппаратной клавиши;
  • onKeyUp() — вызывается при отпускании любой аппаратной клавиши;

Кроме клавиш, есть ещё другие методы обработки пользовательского ввода (здесь не рассматриваются):

  • onTrackballEvent() — срабатывает при движениях трекбола;
  • onTouchEvent() — обработчик событий сенсорного экрана, срабатывает при касании, убирания пальца и при перетаскивании.

Чтобы ваши компоненты и активности реагировали на нажатия клавиш, переопределите обработчики событий onKeyUp() и onKeyDown():

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

Параметр KeyEvent также включает в себя несколько методов: isAltPressed(), isShiftPressed() и isSymPressed(), определяющих, были ли нажаты функциональные клавиши, такие как Alt, Shift или Sym. Статический метод isModifierKey() принимает keyCode и определяет, является ли нажатая клавиша модификатором.

Кнопка Back: Вы уверены, что хотите выйти из программы?

Кнопка Back (Назад) закрывает приложение, точнее текущую активность, но если приложение состоит из одной активности, то это равносильно закрытию всего приложения. В большинстве случаев вам нет никакого дела до неуклюжего пользователя, который по ошибке нажал на кнопку «Back» вместо кнопки Подарить разработчику миллион. Но, если ваша программа, будучи запущенной на телефоне пользователя, потихоньку списывает деньги клиента в счёт Фонда голодных котов, то нужно дать ему шанс задуматься и вывести диалоговое окно с вопросом: «А действительно ли вы хотите выйти из программы?»

Чтобы реализовать такую задачу, нужно переопределить поведение кнопки «Back» через метод активности onBackPressed() следующим образом:

Данный метод появился в Android 2.0. Для более ранних версий использовался стандартный код обработки onKeyDown():

Двойное нажатие на кнопку Back

Другой вариант — выход из приложения при двойном нажатии на кнопку «Back». Удобно в тех случаях, когда считаете, что пользователь может случайно нажать на кнопку, например, во время активной игры. Приложение закроется, если пользователь дважды нажмёт на кнопку в течение двух секунд.

Кнопка Home

Можно отследить нажатие кнопки Home через метод активности onUserLeaveHint():

Обработка кнопки Menu

У телефона, кроме кнопки «Back», есть ещё кнопка «Menu» для вызова команд меню (на старых устройствах). Если необходимо обрабатывать нажатия этой кнопки (например, управление в игре), то используйте следующий код (обычное и долгое нажатие):

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

Другие кнопки

Ну на самом деле можно отслеживать не только нажатие кнопки Меню, но и кнопку Поиска и кнопки увеличения громкости.

Обратите внимание, что для кнопки громкости возвращаем false, т.е. мы не переопределяем поведение кнопки, а оставляем её на усмотрение системы.

Пример работы с кнопками громкости можно посмотреть в статье Рингтоны. Управление громкостью

По такому же принципу работает метод onKeyUp(). Метод onKeyLongPress() можно использовать, если в методе onKeyDown() был задействован метод event.startTracking(), отслеживающий поведение кнопки. В нашем примере мы отслеживали кнопку Volume_Up.

Прячем клавиатуру

Бывает так, что при запуске активности сразу выскакивает клавиатура. Если такое поведение не нравится, то пропишите в манифесте нужное значение у атрибута android:windowSoftInputMode (см. ниже).

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

Код так выглядит, если писать его в Activity. Если расположить его в другом классе, экземпляр Activity нужно передать туда как параметр и вызывать методы как activity.getApplicationContext(), где activity — экземпляр Activity.

Читайте также:  Flash version 9 0 android

Можно избавить компонент от фокуса:

Чтобы принудительно показать клавиатуру, используйте следующий код:

Кстати, повторный вызов метода закроет клавиатуру. Указанный способ не требует наличия элементов View.

Если продолжить тему показа клавиатуры, то может возникнуть следующая ситуация. Допустим у вас есть DialogFragment с EditText. При выводе диалогового окна вам нужно установить фокус на EditText и показать клавиатуру:

Либо используйте тег для нужного EditText.

Изменить вид клавиатуры для EditText

Когда элемент EditText получает фокус, то появляется клавиатура. Можно установить нужный вид клавиатуры через атрибут InputType или программно через метод setInputType():

TYPE_CLASS_DATETIME — дата и время
TYPE_CLASS_NUMBER — цифры
TYPE_CLASS_TEXT — буквы

Переопределяем кнопку Enter

Кроме атрибута InputType можно также использовать атрибут android:imeOptions в компоненте EditText, который позволяет заменить кнопку Enter на клавиатуре на другие кнопки, например, Next, Go, Search и др. Возможны следующие значения:

  • actionUnspecified: Используется по умолчанию. Система сама выбирает нужный вид кнопки (IME_NULL)
  • actionGo: Выводит надпись Go. Действует как клавиша Enter при наборе адреса в адресной строке браузера (IME_ACTION_GO)
  • actionSearch: Выводит значок поиска (IME_ACTION_SEARCH)
  • actionSend: Выводит надпись Send (IME_ACTION_SEND)
  • actionNext: Выводит надпись Next (IME_ACTION_NEXT)
  • actionDone: Выводи надпись Done (IME_ACTION_DONE)

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

Чтобы реагировать на нажатия разных состояний кнопки Enter, необходимо реализовать интерфейс TextView.OnEditorActionListener. Небольшой пример:

В нашем примере если пользователь ищет что-то, не связанное с котом, то кнопка поиска не будет выполнять желание владельца устройства.

Также можно поменять текст на кнопке с помощью атрибута android:imeActionLabel:

Текст на кнопке поменялся, но вот обработка Enter из предыдущего примера у меня перестала работать. Мой неработающий код на память.

Upd: Читатель Максим Г. предложил следующее решение проблемы. Убираем атрибуты imeOptions, imeActionId, imeActionLabel и установим их программно.

По желанию можете отслеживать только у нужного поля. Поставьте дополнительное условие после первого блока if:

Интерфейс OnKeyListener

Чтобы среагировать на нажатие клавиши внутри существующего представления из активности, реализуйте интерфейс OnKeyListener и назначьте его для объекта View, используя метод setOnKeyListener(). Вместо того, чтобы реализовывать отдельные методы для событий нажатия и отпускания клавиш, OnKeyListener использует единое событие onKey().

Используйте параметр keyCode для получения клавиши, которая была нажата. Параметр KeyEvent нужен для распознавания типа события (нажатие представлено константой ACTION_DOWN, а отпускание — ACTION_UP).

Сдвигаем активность

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

Также доступны и другие параметры:

  • stateUnspecified — настройка по умолчанию. Система сама выбирает подходящее поведение клавиатуры.
  • stateUnchanged — клавиатура сохраняет своё последнее состояние (видимое или невидимое), когда активность с текстовым полем получает фокус.
  • stateHidden — клавиатура скрыта, когда открывается активность. Клавиатура появится при наборе текста. Если пользователь переключится на другую активность, то клавиатура будут скрыта, но при возвращении назад клавиатура останется на экране, если она была видима при закрытии активности.
  • stateAlwaysHidden — клавиатура всегда скрывается, если активность получает фокус.
  • stateVisible — клавиатура видима.
  • stateAlwaysVisible — клавиатура становится видимой, когда пользователь открывает активность.
  • adjustResize — размеры компонентов в окне активности могут изменяться, чтобы освободить место для экранной клавиатуры.
  • adjustPan — окно активности и его компоненты не изменяются, а сдвигаются таким образом, чтобы текстовое поле с фокусом не было закрыто клавиатурой.
  • adjustUnspecified — настройка по умолчанию. Система сама выбирает нужный режим.

Параметры с префиксом state можно комбинировать с настройками с префиксом adjust:

Например, чтобы показать клавиатуру при старте активности, используйте stateVisible.

Данные настройки доступны и программно. Например, код для adjustResize:

Кстати, этот код не сработает в полноэкранном режиме (флаг FLAG_FULLSCREEN). Сверяйтесь с документацией.

Узнать выбранный язык на клавиатуре

Для определения текущего языка на клавиатуре можно использовать следующий код.

Следует быть осторожным с примером. На эмуляторе с Android 6.0 пример работал корректно. На реальных устройствах у меня корректно определялся русский язык, но при переключении на английский язык выдавал пустую строку или значение «zz». В этом случае можно прибегнуть к условиям if и проверять ожидаемое значение.

Источник

Animating your keyboard (part 1)

New WindowInsets APIs for checking the keyboard (IME) visibility and size

New in Android 11 is the ability for apps to create seamless transitions between the on screen keyboard being opened and closed, and it’s all powered by lots of improvements to the WindowInsets APIs in Android 11.

Читайте также:  Слежка за андроидом без рут прав

Here you are two examples of it in action on Android 11. It has been integrated into the Google Search app, as well as the Messages app:

So let’s take a look at how you can add this sort of experience to your apps. There are three steps:

  1. First, we need to go edge-to-edge.
  2. The second step is for apps to start reacting to inset animations.
  3. And the third step is by apps taking control of and driving inset animations, if it makes sense for your app.

Each of these steps follow on from each other, so we’ll cover each in separate blog posts. In this first post, we’ll cover going edge-to-edge, and the related API changes in Android 11.

Going edge-to-edge

Last year we introduced the concept of going edge to edge, as a way for apps to make the most of the new gestural navigation in Android 10:

Gesture Navigation: Going edge-to-edge (I)

With Android Q, a new system navigation mode has been added, allowing the user to navigate back, and to the home screen…

As a quick re-cap, going edge to edge results in your app drawing behind the system bars, like you can see on the left.

To quote myself from last year:

By going edge-to-edge, apps will instead be laid out behind the system bars. This is to allow your app content to shine through to create a more immersive experience for your users.

So what has going edge to edge got to do with the keyboard?

Well going edge to edge is actually more than just drawing behind the status and navigation bars. It’s apps taking responsibility for handling those pieces of system UI which might overlap with the app.

The two obvious examples being the status bar and navigation bar, which we mentioned earlier. Then we have the on-screen-keyboard, or IME as it is sometimes referred to; it’s just another piece of system UI to be aware of.

How do apps go edge to edge?

If we flash back to our guidance from last year, going edge to edge is made up of 3 tasks:

  1. Change system bar colors
  2. Request to be laid out fullscreen
  3. Handle visual conflicts

We’re going to skip the first task, because nothing has changed there since last year. The guidance for steps 2 & 3 has been updated with some changes in Android 11. Let’s take a look.

#2: Request to be laid out fullscreen

For the second step, apps needed to use the systemUiVisibility API with a bunch of flags, to request to be laid out fullscreen:

If you were using this API and have updated your compile SDK version to 30, you’ll have seen that all of these APIs are now deprecated.

They’ve been replaced with a single function on Window called setDecorFitsSystemWindows() :

Instead of the many flags, you now pass in a boolean: false if apps want to handle any system window fitting (and thus go fullscreen).

We also have a Jetpack version of the function available in WindowCompat , which was released recently in androidx.core v1.5.0-alpha02 .

So that’s the 2nd step updated.

#3: Handling visual conflicts

Now let’s look at the third step: avoiding overlaps with the system UI, which can be summarised as using the window insets to know where to move content to, to avoid conflicts with the system UI. On Android, insets are represented by the WindowInsets class, and WindowInsetsCompat in AndroidX

If we take a look at WindowInsets before the updates from API 30, the most common inset type to use is the system window insets. These cover the status and navigation bars, and also the keyboard when it is open.

To use WindowInsets , you would typically add an OnApplyWindowInsetsListener to a view, and handle any insets which are passed to it:

Here we’re fetching the system window insets, and then updating the view’s padding to match, which is a very common use case.

There are a number of other inset types available, including the recently added gesture insets from Android 10:

Similar to the systemUiVisibility API, much of the WindowInsets APIs have been deprecated, in favor of new functions to query the insets for different types:

  • getInsets(type: Int) which will return the visible insets for the given types.
  • getInsetsIgnoringVisibility(type: Int) which returns the insets, regardless of whether they’re visible or not.
  • isVisible(type: Int) which returns true if the given type is visible.
Читайте также:  Отключить фоновый режим андроид самсунг

We just mentioned ‘types’ a lot there. These are defined in the WindowInsets. Type class as functions, each returning an integer flag. You can combine multiple types, using a bitwise OR to query for combined types, which we’ll see in a minute.

All of these APIs have been backported to WindowInsetsCompat in AndroidX Core, so you can safely use them back to API 14 (see the release notes for more information).

So if we go back to our example from before, to update it to the new APIs, they become:

The IME type ⌨️

Now the keen eyed 👀 among may have been looking at this list of types, and been looking at one type in particular: the IME type.

Well we can finally answer this StackOverflow question, from over 10 years ago (fashionably late), about how to check the visibility of the keyboard. 🎉

How to check visibility of software keyboard in Android?

To get the current keyboard visibility, we can fetch the root window insets, and then call the isVisible() function, passing in the IME type.

Similarly if we want to find out the height, we can do that too:

If we need to listen to changes to the keyboard, we can use the normal OnApplyWindowInsetsListener , and use the same functions:

Hiding/showing the keyboard

Since we’re on a roll of answering StackOverflow questions, how about this one from 11 years ago, of how to close the keyboard.

How do you close/hide the Android soft keyboard?

Here we are going to introduce another new API in Android 11, called WindowInsetsController .

Apps can get access to a controller from any view, and then show or hide the keyboard by calling either show() or hide() , passing in the IME type:

But hiding and showing the keyboard isn’t all that the controller can do…

WindowInsetsController

Earlier we said that some of the View.SYSTEM_UI_* flags have been deprecated in Android 11, replaced with a new API. Well there were a number of other View.SYSTEM_UI flags available, related to changing the system UI appearance or visibility, including:

  • View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
  • View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  • View.SYSTEM_UI_FLAG_LAYOUT_STABLE
  • View.SYSTEM_UI_FLAG_LOW_PROFILE
  • View.SYSTEM_UI_FLAG_FULLSCREEN
  • View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
  • View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
  • View.SYSTEM_UI_FLAG_IMMERSIVE
  • View.SYSTEM_UI_FLAG_VISIBLE
  • View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
  • View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR

Similar to the others, these have also been deprecated too in API 30, replaced with APIs in WindowInsetsController .

Instead of going through the migration for all of these flags, we’ll cover a few common scenarios and see how to update them:

Immersive modes

Here you can see a drawing app, which hides the System UI to maximise the space available for drawing:

To implement that using WindowInsetsController we use the hide() and show() functions like before, but this time we pass in the system bars type:

The app also uses immersive mode, allowing the user to swipe the system bars back in once hidden. To implement this using WindowInsetsController we change the hide and show behaviour to BEHAVIOR_SHOW_BARS_BY_SWIPE :

Similarly, if you were using sticky immersive mode, this is implemented using the BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE instead:

Status bar content color

The next scenario is around the status bar content color. Here you see two apps:

On the left the app has a dark status bar background, with light content like the time and icons. But if we instead want a light status bar background with dark content, like the right, we can use WindowInsetsController too.

To do that, we can use the setSystemBarsAppearance() function, passing in the APPEARANCE_LIGHT_STATUS_BARS value:

If you instead want to set a dark status bar, by passing in 0 instead to clear the value.

Note: you could implement this in your theme instead, by setting the android:windowLightStatusBar attribute. This might be preferable if you know the value won’t change.

Similarly, the APPEARANCE_LIGHT_NAVIGATION_BARS flag is available which provides the same functionality for the navigation bars.

WindowInsetsController in AndroidX?

Unfortunately a Jetpack version of this API does not exist yet, but we are working on it. Stay tuned.

Going edge-to-edge: ✔️

So that’s the first step done. In the next blog post we’ll investigate the second step: apps reacting to inset animations.

Источник

Оцените статью