Intercept back button from soft keyboard
Yes, it is completely possible to show and hide the keyboard and intercept the calls to the back button. It is a little extra effort as it has been mentioned there is no direct way to do this in the API. The key is to override boolean dispatchKeyEventPreIme(KeyEvent)
within a layout. What we do is create our layout. I chose RelativeLayout since it was the base of my Activity.
<?xml version="1.0" encoding="utf-8"?>
<com.michaelhradek.superapp.utilities.SearchLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.michaelhradek.superapp"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/white">
Inside our Activity we set up our input fields and call the setActivity(...)
function.
private void initInputField() {
mInputField = (EditText) findViewById(R.id.searchInput);
InputMethodManager imm =
(InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,
InputMethodManager.HIDE_IMPLICIT_ONLY);
mInputField.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId,
KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
performSearch();
return true;
}
return false;
}
});
// Let the layout know we are going to be overriding the back button
SearchLayout.setSearchActivity(this);
}
Obviously, the initInputField()
function sets up the input field. It also enables the enter key to execute the functionality (in my case a search).
@Override
public void onBackPressed() {
// It's expensive, if running turn it off.
DataHelper.cancelSearch();
hideKeyboard();
super.onBackPressed();
}
So when the onBackPressed()
is called within our layout we then can do whatever we want like hide the keyboard:
private void hideKeyboard() {
InputMethodManager imm = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mInputField.getWindowToken(), 0);
}
Anyway, here is my override of the RelativeLayout.
package com.michaelhradek.superapp.utilities;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.RelativeLayout;
/**
* The root element in the search bar layout. This is a custom view just to
* override the handling of the back button.
*
*/
public class SearchLayout extends RelativeLayout {
private static final String TAG = "SearchLayout";
private static Activity mSearchActivity;;
public SearchLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SearchLayout(Context context) {
super(context);
}
public static void setSearchActivity(Activity searchActivity) {
mSearchActivity = searchActivity;
}
/**
* Overrides the handling of the back key to move back to the
* previous sources or dismiss the search dialog, instead of
* dismissing the input method.
*/
@Override
public boolean dispatchKeyEventPreIme(KeyEvent event) {
Log.d(TAG, "dispatchKeyEventPreIme(" + event + ")");
if (mSearchActivity != null &&
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
KeyEvent.DispatcherState state = getKeyDispatcherState();
if (state != null) {
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0) {
state.startTracking(event, this);
return true;
} else if (event.getAction() == KeyEvent.ACTION_UP
&& !event.isCanceled() && state.isTracking(event)) {
mSearchActivity.onBackPressed();
return true;
}
}
}
return super.dispatchKeyEventPreIme(event);
}
}
Unfortunately I can't take all the credit. If you check the Android source for the quick SearchDialog box you will see where the idea came from.
How to intercept flutter back-button when keyboard is shown
you can use the keyboard_visibility package to achieve this.
Working Example
the following code displays a SnackBar
once the keyboard is dismissed.
import 'package:flutter/material.dart';
import 'package:keyboard_visibility/keyboard_visibility.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
GlobalKey<ScaffoldState> _key;
@override
void initState() {
super.initState();
_key = GlobalKey<ScaffoldState>();
KeyboardVisibilityNotification().addNewListener(
onHide: () {
_key.currentState.showSnackBar(
SnackBar(
content: Text("Keyboard closed"),
),
);
},
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _key,
body: Center(
child: TextField(),
),
),
);
}
}
Android - onBackPressed close soft keyboard AND activity
You can create customized view and implement onKeyPreIme(keyCode: Int, event: KeyEvent)
and check for keyCode == KeyEvent.KEYCODE_BACK
event.
Hope this answer will explain it to you furthermore.
Edited:
try to implement these for your SearchView
:
searchInput.setOnQueryTextFocusChangeListener{ _, b->
if(!b){
searchview.isIconified = true
finish()
}
}
EditText with soft keyboard and Back button
You can override when the keyboard disappears using this method:
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK &&
event.getAction() == KeyEvent.ACTION_UP) {
// Do your thing here
return false;
}
return super.dispatchKeyEvent(event);
}
Taken from my other answer @ : Android: Error popup on EditText doesn't move down when keyboard goes away
Android : Handle back button click when keyboard is open for EditText
I did few modifications to @GuanHongHuang's answer and now I am able to do this by these 3 steps:
1. Creating Custom EditText Class to handle Back Press:
public class CustomEditTextWithBackPressEvent extends androidx.appcompat.widget.AppCompatEditText {
private MyEditTextListener onBackPressListener;
public CustomEditTextWithBackPressEvent(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setOnBackPressListener(MyEditTextListener onBackPressListener) {
this.onBackPressListener = onBackPressListener;
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK &&
event.getAction() == KeyEvent.ACTION_UP) {
//back button pressed
if (Objects.requireNonNull(ViewCompat.getRootWindowInsets(getRootView())).isVisible(WindowInsetsCompat.Type.ime())) {
//keyboard is open
onBackPressListener.callback();
}
return false;
}
return super.dispatchKeyEvent(event);
}
public interface MyEditTextListener {
void callback();
}
}
2. Replace your normal EditText with this CustomEditTextWithBackPressEvent in XML
<CustomEditTextWithBackPressEvent
android:id="@+id/etSearch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/search_hint"
android:imeOptions="actionSearch"
android:inputType="text"
android:maxLines="1" />
3. Handle Back Press:
binding.etSearch.setOnBackPressListener(() -> {
//handle click
//your code here
});
Related Topics
Bitmapfactory Oom Driving Me Nuts
The Number of Method References in a .Dex File Cannot Exceed 64K API 17
Googleservice Failed to Initialize
Finish an Activity from Another Activity
How to Add Apache Http API (Legacy) as Compile-Time Dependency to Build.Grade for Android M
Unable Instantiate Android.Gms.Maps.Mapfragment
Google Maps Android API V2 - Detect Touch on Map
Failed to Resolve: Com.Google.Firebase:Firebase-Core:9.0.0
How to Disable Action Bar Permanently
Date and Time Change Listener in Android
How to Get the Touch Position in Android
Listview Reusing Views When ... I Don't Want It To
Couldn't Load Memtrack Module Logcat Error
Android: Out of Memory Exception in Gallery