Hide soft keyboard
Скрытие soft keyboard
При тапе EditText открывается soft keyboard, однако автоматически она не закрывается. Если не закрыть клавиатуру программно, она будет показана на всех остальных фрагментах. При работе с эмулятором, можно упустить этот момент, т.к. в эмуляторе soft keyboard открывается отдельно.
Анализ реализации hide soft keyboard
- скрытие при потере фокуса
- скрытие при onPause, onStop
- скрытие при нажатии на другие элементы экрана
- скрытие при scroll контента
- скрытие при onClick спец. кнопке на клаве (в edit text)
Обзор open sourse
Alkee
Управление клавиатурой сделано в виде расширения фрагмента. Клавиатура скрывается после добавления задачи.
FragmentExtensions.kt
/**
* Hides the opened soft keyboard from the [Fragment].
*/
fun Fragment.showKeyboard() {
val imm = context?.getSystemService(Activity.INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)
}
/**
* Hides the opened soft keyboard from the [Fragment].
*/
fun Fragment.hideKeyboard() {
val imm = context?.getSystemService(Activity.INPUT_METHOD_SERVICE) as? InputMethodManager
imm?.hideSoftInputFromWindow(view?.windowToken, 0)
}
Открытие клавиатуры при запуске фрагмента
CategoryAddFragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Timber.d("onViewCreated()")
openSoftKeyboard()
initComponents()
}
private fun openSoftKeyboard() {
edittext_categorynew_description.requestFocus()
showKeyboard()
}
Скрытие клавиатуры после ввода задачи
Cделано вместе с задержкой для плавной анимации.
TaskListFragment
private fun onInsertTask(description: String) {
hideKeyboard()
withDelay(INSERT_DELAY) { viewModel.addTask(description)}
}
companion object {
private const val INSERT_DELAY = 200L
}
HandlerExtensions.kt
/**
* Runs a code block with a given delay.
*
* @param delay the delay (in milliseconds) until the code block will be executed
* @param func the function to be executed
*/
fun withDelay(delay: Long, func: () -> Unit) {
Handler().postDelayed({ func() }, delay)
}
SimpleNote
Скрытие клавитуры при переключение viewPager. Клавиатура появляется в onResume, если есть фокус на content и скрывается в onPause. NoteEditorFragment.
mViewPager.addOnPageChangeListener(
new NoteEditorViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
if (position == INDEX_TAB_PREVIEW) {
DisplayUtils.hideKeyboard(mViewPager);
}
Скрытие и показ клавиатуры
@Override
public void onResume() {
super.onResume();
if (mContentEditText != null) {
mContentEditText.setTextSize(TypedValue.COMPLEX_UNIT_SP, PrefUtils.getFontSize(requireContext()));
if (mContentEditText.hasFocus()) {
showSoftKeyboard();
}
}
}
private void showSoftKeyboard() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (getActivity() == null) {
return;
}
InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager != null) {
inputMethodManager.showSoftInput(mContentEditText, 0);
}
}
}, 100);
}
@Override
public void onPause() {
super.onPause(); // Always call the superclass method first
mIsPaused = true;
// Hide soft keyboard if it is showing...
DisplayUtils.hideKeyboard(mContentEditText);
saveNote();
AppLog.add(Type.SCREEN, "Paused (NoteEditorFragment)");
}
/**
* Hides the keyboard for the given {@link View}. Since no {@link InputMethodManager} flag is
* used, the keyboard is forcibly hidden regardless of the circumstances.
*/
public static void hideKeyboard(@Nullable final View view) {
if (view == null) {
return;
}
InputMethodManager inputMethodManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager != null) {
inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
### Tasks Скрытие клавиатуры onMenuItemClick, onClickFab, closeSearch
override fun onMenuItemClick(item: MenuItem): Boolean {
AndroidUtilities.hideKeyboard(activity)
В новом фрагменте.
private var showKeyboard = false
override fun onCreate(savedInstanceState: Bundle?) {
if (savedInstanceState == null) {
showKeyboard = model.isNew && isNullOrEmpty(model.title)
}
}
override fun onResume() {
super.onResume()
if (showKeyboard) {
binding.title.requestFocus()
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(binding.title, InputMethodManager.SHOW_IMPLICIT)
}
}
### Lawnchair Скрытие клавиатуры onScroll и перенос фокуса на list_results
listResults.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
if (dy != 0) {
hideKeyboard()
}
}
})
private fun hideKeyboard() {
val view = currentFocus ?: return
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(view.windowToken, 0)
list_results.requestFocus()
}
Тестирование Espresso
Добавляем метод для проверки открытия клавиатуры в базовый экран.
fun isKeyboardOpen(): Boolean {
val checkKeyboardCmd = "dumpsys input_method | grep mInputShown"
try {
return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
.executeShellCommand(checkKeyboardCmd).contains("mInputShown=true")
} catch (e: IOException) {
throw RuntimeException("Keyboard check failed", e)
}
}
Примеры тестов
@Test
fun hideKeyBoardWhenClickOnCatalogBack() {
// Given
val screen = navigateToListDetailedEdit()
screen.enterText("example")
screen.clickOnPlus()
sleep(500)
// When
screen.clickOnOCatalogOpen()
sleep(500)
// Then
assertFalse(screen.isKeyboardOpen())
device.pressBack()
assertFalse(screen.isKeyboardOpen())
}
Ручное тестирование
- на genumotion нужно вручную показывать клавиатуру
- методы onBackPressed (кнопка на эмуляторе) закрывает клавиатуру по умолчанию
- при нажатии на
back arrow
на toolbar, автоматически не закрывает
Анализ поведения программ
show | onBackPressed | loosing focus | open other fragment | |
---|---|---|---|---|
Simple note | after tap | hide | show | hide |
Google keep | after tap | hide | show | по-разному |
TickTick | after tap | hide | hide | hide |
Alkee | onViewCreated | hide | hide | hide |
Сообщения | при запуске | hide | show | по-разному |
- Сообщения: keyboard show -> display other a screen -> on back -> display keyboard
- Google keep: keyboard show -> display bottom sheet-> on back -> display keyboard
Выводы по использованию
-
Для быстрого ввода информации, удобнее когда клавиатура не скрывается.
-
Если форма предполагает одну форму для редактирования, то логичнее клавиатуру отрывать сразу, не после тапа.
- On back сначала закрывается клавиатура
- Hide keyboard при открытии диалогов, переходе на другие фрагменты