Мягкая клавиатура открывает и закрывает слушателя в действии в Android

У меня есть Activity, где есть 5 EditText. Когда пользователь нажимает на первый EditText, открывается программная клавиатура, чтобы ввести в нее какое-то значение. Я хочу установить для некоторых других View видимость Gone, когда открывается программная клавиатура, а также когда пользователь нажимает первый EditText, а также когда программная клавиатура закрывается с того же EditText при нажатии кнопки «Назад». Затем я хочу сделать видимыми некоторые другие View.

Есть ли какой-нибудь прослушиватель, обратный вызов или какой-либо способ взлома, когда программная клавиатура открывается после щелчка по первому EditText в Android?


person N Sharma    schedule 09.08.2014    source источник
comment
Нет. Таких слушателей нет. Есть хаки для достижения того, что вы пытаетесь сделать. Вот возможный подход: Как отправить событие указателя в Android.   -  person Vikram    schedule 09.08.2014
comment
@Vikram Я не ищу trying to detect the virtual keyboard height in Android.   -  person N Sharma    schedule 09.08.2014
comment
Я знаю. Если вы пройдете через код, вы увидите, как определяется высота. Отправляется событие указателя - ›два случая =› 1. если клавиатура открыта = ›& если положение указателя X и Y падает на клавиатуру или над ней =› SecurityException = ›уменьшите Y и повторите попытку =› до тех пор, пока не исчезнет исключение выброшено = ›текущее значение Y - высота клавиатуры. 2. если клавиатура не открыта = ›нет SecurityException.   -  person Vikram    schedule 09.08.2014
comment
Как это применимо к вашему сценарию? Отправьте событие указателя, скажем, на 2/3 высоты экрана. Если выброшено SecurityException = ›клавиатура открыта. Иначе клавиатура закрыта.   -  person Vikram    schedule 09.08.2014
comment
@Vikram Я хочу это только для первого EditText, а не для других EditText. Как я могу это отличить?   -  person N Sharma    schedule 09.08.2014
comment
Понятно. Вы действительно имеете в виду listener. Я совершенно уверен, что в Android их нет. Наверное, еще кто-нибудь может предложить другой взлом.   -  person Vikram    schedule 09.08.2014
comment
@Vikram Да, подождем другого ответа.   -  person N Sharma    schedule 09.08.2014
comment
Попробуйте добавить слушателя к вашему первому редактируемому тексту   -  person Tejas    schedule 05.09.2014
comment
@Tejas Я не уверен, о каком слушателе вы говорите.   -  person N Sharma    schedule 05.09.2014
comment
@Williams - Я говорил о addTextChangedListener. Ману также указал 1 способ использования Focus Listener.   -  person Tejas    schedule 07.09.2014
comment
Посмотрите на эту ссылку, она отлично работает stackoverflow.com/questions/2150078/   -  person Chandramouli    schedule 10.09.2014
comment
попробуйте библиотеку .. у меня работает! android-arsenal.com/details/1/2519   -  person Mangesh    schedule 23.11.2016
comment
Возможный дубликат уведомления при отображении / закрытии виртуальной клавиатуры для EditText?   -  person Edward Brey    schedule 26.01.2019
comment
Возможный дубликат Android: обнаружение открытия программной клавиатуры   -  person AbdelHady    schedule 14.11.2019


Ответы (31)


Это работает, только если android:windowSoftInputMode вашей активности в манифесте установлено на adjustResize. Вы можете использовать прослушиватель макета, чтобы увидеть, изменен ли размер корневого макета вашего действия с помощью клавиатуры.

Для своей деятельности я использую что-то вроде следующего базового класса:

public class BaseActivity extends Activity {
    private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
            int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();

            LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(BaseActivity.this);

            if(heightDiff <= contentViewTop){
                onHideKeyboard();

                Intent intent = new Intent("KeyboardWillHide");
                broadcastManager.sendBroadcast(intent);
            } else {
                int keyboardHeight = heightDiff - contentViewTop;
                onShowKeyboard(keyboardHeight);

                Intent intent = new Intent("KeyboardWillShow");
                intent.putExtra("KeyboardHeight", keyboardHeight);
                broadcastManager.sendBroadcast(intent);
            }
        }
    };

    private boolean keyboardListenersAttached = false;
    private ViewGroup rootLayout;

    protected void onShowKeyboard(int keyboardHeight) {}
    protected void onHideKeyboard() {}

    protected void attachKeyboardListeners() {
        if (keyboardListenersAttached) {
            return;
        }

        rootLayout = (ViewGroup) findViewById(R.id.rootLayout);
        rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);

        keyboardListenersAttached = true;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (keyboardListenersAttached) {
            rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
        }
    }
}

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

Макет xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:id="@+id/rootLayout"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">              

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        >

        <!-- omitted for brevity -->

    </ScrollView>

    <LinearLayout android:id="@+id/bottomContainer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <!-- omitted for brevity -->

    </LinearLayout>

</LinearLayout>

И активность:

public class TestActivity extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_activity);

        attachKeyboardListeners();
    }

    @Override
    protected void onShowKeyboard(int keyboardHeight) {
        // do things when keyboard is shown
        bottomContainer.setVisibility(View.GONE);
    }

    @Override
    protected void onHideKeyboard() {
        // do things when keyboard is hidden
        bottomContainer.setVisibility(View.VISIBLE);
    }        
}
person Jaap van Hengstum    schedule 05.09.2014
comment
Полагаю, это сработает как решение данной проблемы. - person MKJParekh; 12.09.2014
comment
+1 Ага Это идеальное решение моей проблемы. - person N Sharma; 14.09.2014
comment
Привет, вы использовали getTop () в Window.ID_ANDROID_CONTENT. Получить топ не работает для меня. здесь всегда 0, это работает так, как будто вместо этого предполагается использовать getHeight (). - person Daniele Segato; 23.02.2015
comment
привет, я использовал ваше решение, но в onShowKeyboard () после bottomcontainer.setVisibility (GONE) я пытаюсь прокрутить выше ScrollView, чтобы показать editText в ScrollView, и я потерпел неудачу, следующий код - person suyanlu; 18.03.2015
comment
: protected void onShowKeyboard (final int keyboardHeight) {если (selectedFragment.getTagText (). equals (PersonalInfoFragment.class.getSimpleName ())) {mRgBottomBanner.setVisibility (View.GONE); final ScrollView bsv = ButterKnife.findById (это, R.id.bsv); if (bsv! = null) {bsv.post (new Runnable () {@Override public void run () {bsv.smoothScrollTo (0, 0-keyboardHeight);}}); } Есть что-нибудь, что я не прав? - person suyanlu; 18.03.2015
comment
На самом деле это решение потребляет много памяти. - person Shubham A.; 26.10.2015
comment
Хитрое, но красивое решение. Я использовал логическое значение, которое сохраняет последнее состояние клавиатуры в памяти, чтобы обратный вызов / широковещательная передача не происходили постоянно с одним и тем же значением. По моим тестам, использование памяти в порядке. - person shkschneider; 22.01.2016
comment
откуда вы берете rootLayout = (ViewGroup) findViewById(R.id.rootLayout);от? - person CommonSenseCode; 11.02.2016
comment
У меня почему-то не работает, всегда вызывает onShowKeyboard, открываю или закрываю. Я использую findViewById (android.R.id.content), может в этом проблема? - person McSullivan; 26.02.2016
comment
getWindow (). findViewById (Window.ID_ANDROID_CONTENT) .getTop () всегда возвращает 0. - person FarshidABZ; 18.06.2017
comment
Хорошее решение, хотя в моем случае из коробки не вышло. Пришлось добавить contentViewTop = contentViewTop + 100 после инициализации - person tsig; 20.09.2017
comment
если переместить слушателя в абстрактный класс (BaseClass) и предоставить там проверки? - person Suraj Shingade; 21.03.2018
comment
@tsig ваше решение +100 зависит от конкретного экрана. Сбой на планшетах и ​​телефонах hdpi. Я использовал поправку на десять процентов от высоты устройства. Это означает, что если высота просмотра меньше screenHeight - 10%, клавиатура открыта. иначе клавиатура закрыта. Вот мой contentViewTop в onGlobalLayout: contentViewTop = (getWindow (). GetDecorView (). GetBottom () / 10) - person ilker; 30.04.2019
comment
AdjustResize не работает (размер макета не изменяется), если у вашей активности прозрачные панели состояния / навигации - person blinker; 05.05.2021
comment
Что здесь делает broadcastManager? - person ericn; 13.07.2021

Кусок торта с великолепной библиотекой KeyboardVisibilityEvent

KeyboardVisibilityEvent.setEventListener(
    getActivity(),
    new KeyboardVisibilityEventListener() {
        @Override
        public void onVisibilityChanged(boolean isOpen) {
            // Ah... at last. do your thing :)
        }
    });

Кредиты для Ясухиро ШИМИЗУ

person Gal Rom    schedule 26.07.2016
comment
Это не сработает, потому что клавиатуры не имеют статической высоты, а высота в этой библиотеке установлена ​​на 100dp. - person milosmns; 12.01.2017
comment
@milosmns высота порога 100dp используется для обнаружения клавиатуры. Никаких предположений о фактической высоте клавиатуры не делается. - person Nino van Hooff; 16.01.2018
comment
Это все еще жестко запрограммировано. Мульти окно? Разделенный вид Samsung? Картинка в картинке? Также есть минимальная однорядная клавиатура, которая будет ниже 100dp. Здесь нет серебряной пули ... - person milosmns; 16.01.2018
comment
Поскольку для этой проблемы нет никаких уловок, кажется, что это проще всего реализовать, и просто вернитесь к коду, над которым действительно хотите работать :) - person Machine Tribe; 31.08.2018
comment
Это, безусловно, лучший ответ, абсолютно надежный на любом устройстве. - person Pelanes; 12.07.2019
comment
@Pelanes совершенно нет. Просто посмотрите на некоторые открытые вопросы - person Tim; 26.07.2019
comment
@TimCastelijns по моему опыту, я пробовал несколько вариантов, и это тот, который лучше работает на большинстве устройств. Возможно, это не идеально, но у меня было много проблем с этой функцией на Nexus 5X и других устройствах Nexus, и она отлично работала. - person Pelanes; 01.08.2019
comment
@Pelanes это тот, который лучше работает на большинстве устройств, поэтому не утверждайте, что он полностью надежен на любом устройстве. - person Tim; 01.08.2019
comment
Обидно, что такая базовая функциональность не имеет нативного решения в Android! Google, кажется, запихивает столько ненужной чуши в новые версии Android, но не исправляет такие важные недостатки ... - person doctorram; 28.10.2020
comment
Он не работает, если установлен в файле-манифесте android:windowSoftInputMode="adjustNothing". - person Dharmishtha; 04.01.2021

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

Может быть, достаточно установить прослушиватель фокуса на текст редактирования:

yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            //got focus
        } else {
            //lost focus
        }
   }
});
person Manuel Allenspach    schedule 05.09.2014
comment
Предположим, я нажимаю на edittext, тогда он setOnFocusChangeListener listener будет вызываться, затем я нажимаю обратно, он закрывает клавиатуру, но не нажимаю на другие представления, теперь я снова нажимаю на тот же edittext, который уже имеет фокус, тогда что произойдет? - person N Sharma; 12.09.2014
comment
@Williams Я не совсем уверен, но подозреваю, что onFocusChange() не будет вызван. - person Manuel Allenspach; 12.09.2014
comment
Вы правы, тогда как справиться с этой ситуацией, поэтому я задаю этот вопрос щедрости - person N Sharma; 12.09.2014
comment
это не мой вопрос. Прочтите мой вопрос еще раз - у меня есть Activity, где есть 5 EditText. Когда пользователь нажимает первый EditText, затем открывается мягкая клавиатура, чтобы ввести в него какое-то значение. Я хочу установить для некоторой другой видимости View значение Gone, когда мягкая клавиатура открывается, когда пользователь нажимает на первый EditText и когда мягкая клавиатура закрывается из того же EditText при обратном нажатии, тогда я хочу установить видимость другого View видимости. Есть ли какой-либо слушатель, обратный вызов или какой-либо взлом, когда мягкая клавиатура открывается при нажатии на первый EditText в Android? - person N Sharma; 14.09.2014
comment
Когда вы нажимаете кнопку "Назад", клавиатура отключается, когда onfocus слушатель никогда не звонит, это то, что я ищу, а не то, что вы предлагаете. - person N Sharma; 14.09.2014
comment
Ребята не смотрят на этот ответ, потому что он говорит что-то другое, чего я даже не понимаю. - person N Sharma; 14.09.2014
comment
В любом случае, у меня это не работает ... Когда виртуальная клавиатура скрыта, в EditText не произошло никакого изменения фокуса ... Поэтому я не могу получить уведомление от этого Listener. - person Licat Julius; 06.06.2018
comment
Если пользователь просто закрывает клавиатуру (стрелка вниз), фокус все еще находится на EditText, но клавиатура закрыта - person Choletski; 24.07.2019

Для деятельности:

    final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();

                activityRootView.getWindowVisibleDisplayFrame(r);

                int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 100) { 
                 //enter your code here
                }else{
                 //enter code for hid
                }
            }
        });

Для фрагмента:

    view = inflater.inflate(R.layout.live_chat_fragment, null);
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                //r will be populated with the coordinates of your view that area still visible.
                view.getWindowVisibleDisplayFrame(r);

                int heightDiff = view.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 500) { // if more than 100 pixels, its probably a keyboard...

                }
            }
        });
person M Singh Karnawat    schedule 21.07.2016
comment
Использовал его для активности, но вместо сравнения с представлением я сравнивал с размером экрана. работает отлично - person Roee; 22.01.2017
comment
Лучше было бы сравнить heightDiff с высотой в dp, а не в пикселях. Он может существенно различаться. - person Leo Droidcoder; 13.11.2017
comment
Нужен ли для этого android:windowSoftInputMode="adjustResize" в манифесте? - person LiuWenbin_NO.; 16.03.2018
comment
android: windowSoftInputMode = adjustResize android: configChanges = ориентация | клавиатура | keyboardHidden - person M Singh Karnawat; 16.03.2018
comment
У меня это работает, но у меня есть вопрос. Это стоит много ресурсов? - person Licat Julius; 06.06.2018

Ответ Jaap не будет работать для AppCompatActivity. Вместо этого получите высоту строки состояния, панели навигации и т. Д. И сравните с размером окна вашего приложения.

Вот так:

    private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // navigation bar height
        int navigationBarHeight = 0;
        int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
        if (resourceId > 0) {
            navigationBarHeight = getResources().getDimensionPixelSize(resourceId);
        }

        // status bar height
        int statusBarHeight = 0;
        resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = getResources().getDimensionPixelSize(resourceId);
        }

        // display window size for the app layout
        Rect rect = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);

        // screen height - (user app height + status + nav) ..... if non-zero, then there is a soft keyboard
        int keyboardHeight = rootLayout.getRootView().getHeight() - (statusBarHeight + navigationBarHeight + rect.height());

        if (keyboardHeight <= 0) {
            onHideKeyboard();
        } else {
            onShowKeyboard(keyboardHeight);
        }
    }
};
person Richard    schedule 21.06.2016
comment
Кажется, работает неплохо, за одним исключением: разрывы в режиме разделенного экрана. В остальном это здорово. - person MCLLC; 28.07.2017

Можешь попробовать:

private void initKeyBoardListener() {
    // Минимальное значение клавиатуры. 
    // Threshold for minimal keyboard height.
    final int MIN_KEYBOARD_HEIGHT_PX = 150;
    // Окно верхнего уровня view. 
    // Top-level window decor view.
    final View decorView = getWindow().getDecorView();
    // Регистрируем глобальный слушатель. Register global layout listener.
    decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        // Видимый прямоугольник внутри окна. 
        // Retrieve visible rectangle inside window.
        private final Rect windowVisibleDisplayFrame = new Rect();
        private int lastVisibleDecorViewHeight;

        @Override
        public void onGlobalLayout() {
            decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
            final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();

            if (lastVisibleDecorViewHeight != 0) {
                if (lastVisibleDecorViewHeight > visibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX) {
                    Log.d("Pasha", "SHOW");
                } else if (lastVisibleDecorViewHeight + MIN_KEYBOARD_HEIGHT_PX < visibleDecorViewHeight) {
                    Log.d("Pasha", "HIDE");
                }
            }
            // Сохраняем текущую высоту view до следующего вызова.
            // Save current decor view height for the next call.
            lastVisibleDecorViewHeight = visibleDecorViewHeight;
        }
    });
}
person Pavel Dolbik    schedule 05.05.2017
comment
Спасибо, Долбик! :) - person AlexS; 25.12.2019

Приведенный ниже код работает для меня,

mainLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (mainLayout != null) {
                int heightDiff = mainLayout.getRootView().getHeight() - mainLayout.getHeight();
                if (heightDiff > dpToPx(getActivity(), 200)) { 
                   //keyboard is open
                } else {
                   //keyboard is hide
                }
            }
        }
    });
person Vinoj Vetha    schedule 12.03.2019
comment
Что такое mainLayout? И heightDiff всегда равен 0, когда текст находится в верхней части представления. - person Md Imran Choudhury; 03.08.2020

Вы можете использовать мою функцию расширения Rx (Kotlin).

/**
 * @return [Observable] to subscribe of keyboard visibility changes.
 */
fun AppCompatActivity.keyboardVisibilityChanges(): Observable<Boolean> {

    // flag indicates whether keyboard is open
    var isKeyboardOpen = false

    val notifier: BehaviorSubject<Boolean> = BehaviorSubject.create()

    // approximate keyboard height
    val approximateKeyboardHeight = dip(100)

    // device screen height
    val screenHeight: Int = getScreenHeight()

    val visibleDisplayFrame = Rect()

    val viewTreeObserver = window.decorView.viewTreeObserver

    val onDrawListener = ViewTreeObserver.OnDrawListener {

        window.decorView.getWindowVisibleDisplayFrame(visibleDisplayFrame)

        val keyboardHeight = screenHeight - (visibleDisplayFrame.bottom - visibleDisplayFrame.top)

        val keyboardOpen = keyboardHeight >= approximateKeyboardHeight

        val hasChanged = isKeyboardOpen xor keyboardOpen

        if (hasChanged) {
            isKeyboardOpen = keyboardOpen
            notifier.onNext(keyboardOpen)
        }
    }

    val lifeCycleObserver = object : GenericLifecycleObserver {
        override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event?) {
            if (source.lifecycle.currentState == Lifecycle.State.DESTROYED) {
                viewTreeObserver.removeOnDrawListener(onDrawListener)
                source.lifecycle.removeObserver(this)
                notifier.onComplete()
            }
        }
    }

    viewTreeObserver.addOnDrawListener(onDrawListener)
    lifecycle.addObserver(lifeCycleObserver)

    return notifier
            .doOnDispose {
                viewTreeObserver.removeOnDrawListener(onDrawListener)
                lifecycle.removeObserver(lifeCycleObserver)
            }
            .onTerminateDetach()
            .hide()
}

Пример:

(context as AppCompatActivity)
                    .keyboardVisibilityChanges()
                    .subscribeBy { isKeyboardOpen ->
                        // your logic
                    }
person Vlad    schedule 31.07.2018
comment
У меня не работает. Не удается найти методы dip() и getScreenHeight() - person Marcin Kunert; 17.05.2019
comment
@MarcinKunert - это просто функция расширения, которая поможет вам преобразовать пиксели в dp и получить высоту экрана. Если хотите, могу привести пример таких функций. - person Vlad; 18.05.2019
comment
GenericLifecycleObserver устарел? любое решение? - person Zainal Fahrudin; 01.10.2019

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

implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:3.0.0-RC2'

А затем вы просто используете этот сегмент кода для проверки видимости клавиатуры.

KeyboardVisibilityEvent.setEventListener(this, new KeyboardVisibilityEventListener() {
        
@Override
  public void onVisibilityChanged(boolean isOpen) {

if (isOpen) 
  Toast.makeText(MainActivity.this, "keyboard opened",Toast.LENGTH_SHORT).show();
else 
  Toast.makeText(MainActivity.this, "keyboard hidden", Toast.LENGTH_SHORT).show();
}
});

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

        UIUtil.showKeyboard(this,edittext_to_be_focused);
        UIUtil.hideKeyboard(this);
person Nitin Bagdi    schedule 05.09.2020

Если можете, попробуйте расширить EditText и переопределить метод onKeyPreIme.

@Override
public void setOnEditorActionListener(final OnEditorActionListener listener) {
    mEditorListener = listener; //keep it for later usage
    super.setOnEditorActionListener(listener);
}

@Override
public boolean onKeyPreIme(final int keyCode, final KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        if (mEditorListener != null) {
            //you can define and use custom listener,
            //OR define custom R.id.<imeId>
            //OR check event.keyCode in listener impl
            //* I used editor action because of ButterKnife @
            mEditorListener.onEditorAction(this, android.R.id.closeButton, event);
        }
    }
    return super.onKeyPreIme(keyCode, event);
}

Как его продлить:

  1. Реализуйте прослушивание onFocus и объявите onKeyboardShown
  2. объявить onKeyboardHidden

Я думаю, что пересчет высоты экрана не на 100% успешен, как упоминалось ранее. Чтобы быть ясным, переопределение onKeyPreIme не вызывается в методах «скрыть программную клавиатуру программно», НО, если вы делаете это где-нибудь, вы должны выполнять там логику «onKeyboardHidden» и не создавать комплексных решений.

person zegee29    schedule 16.07.2017

Это будет работать без необходимости изменять android:windowSoftInputMode вашей активности

Шаг 1: расширите класс EditText и переопределите эти два:

@Override
public void setOnEditorActionListener(final OnEditorActionListener listener) {
    mEditorListener = listener;
    super.setOnEditorActionListener(listener);
}

@Override
public boolean onKeyPreIme(final int keyCode, final KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        if (mEditorListener != null) {
            mEditorListener.onEditorAction(this, android.R.id.closeButton, event);
        }
    }
    return super.onKeyPreIme(keyCode, event);
}

Шаг 2: создайте эти два в своей деятельности:

private void initKeyboard() {
    final AppEditText editText = findViewById(R.id.some_id);
    editText.setOnFocusChangeListener(new OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            setKeyboard(hasFocus);
        }
    });
    editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (event == null || event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                editText.clearFocus();
            }
            return false;
        }
    });
}

public void setKeyboard(boolean isShowing) {
    // do something
}

*** помните, чтобы clearFocus работал, вы должны сделать родительский или первый дочерний элемент в родительской иерархии доступным для фокусировки.

    setFocusableInTouchMode(true);
    setFocusable(true);
person kasra fallen    schedule 02.06.2018

Для использования в Kotlin внутри фрагмента, что является обычным вариантом использования, это очень просто с библиотекой KeyboardVisibilityEvent.

В build.gradle:

implementation 'net.yslibrary.keyboardvisibilityevent:keyboardvisibilityevent:3.0.0-RC2'

Во фрагменте:

activity?.let {
    KeyboardVisibilityEvent.setEventListener(it,object: KeyboardVisibilityEventListener {
        override fun onVisibilityChanged(isOpen: Boolean) {
            if (isOpen) Toast.makeText(context,"Keyboard is opened",Toast.LENGTH_SHORT).show()
            else Toast.makeText(context,"Keyboard is closed",Toast.LENGTH_SHORT).show()
        }
    })
}

Источник и кредиты

person F.Mysir    schedule 04.01.2021

Используйте этот класс,

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

public class SoftKeyboard implements View.OnFocusChangeListener
{
private static final int CLEAR_FOCUS = 0;

private ViewGroup layout;
private int layoutBottom;
private InputMethodManager im;
private int[] coords;
private boolean isKeyboardShow;
private SoftKeyboardChangesThread softKeyboardThread;
private List<EditText> editTextList;

private View tempView; // reference to a focused EditText

public SoftKeyboard(ViewGroup layout, InputMethodManager im)
{
    this.layout = layout;
    keyboardHideByDefault();
    initEditTexts(layout);
    this.im = im;
    this.coords = new int[2];
    this.isKeyboardShow = false;
    this.softKeyboardThread = new SoftKeyboardChangesThread();
    this.softKeyboardThread.start();
}

public void openSoftKeyboard()
{
    if(!isKeyboardShow)
    {
        layoutBottom = getLayoutCoordinates();
        im.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);
        softKeyboardThread.keyboardOpened();
        isKeyboardShow = true;
    }
}

public void closeSoftKeyboard()
{
    if(isKeyboardShow)
    {
        im.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
        isKeyboardShow = false;
    }
}

public void setSoftKeyboardCallback(SoftKeyboardChanged mCallback)
{
    softKeyboardThread.setCallback(mCallback);
}

public void unRegisterSoftKeyboardCallback()
{
    softKeyboardThread.stopThread();
}

public interface SoftKeyboardChanged 
{
    public void onSoftKeyboardHide();
    public void onSoftKeyboardShow();   
}

private int getLayoutCoordinates()
{
    layout.getLocationOnScreen(coords);
    return coords[1] + layout.getHeight();
}

private void keyboardHideByDefault()
{
    layout.setFocusable(true);
    layout.setFocusableInTouchMode(true);
}

/*
 * InitEditTexts now handles EditTexts in nested views
 * Thanks to Francesco Verheye ([email protected])
 */
private void initEditTexts(ViewGroup viewgroup) 
{
    if(editTextList == null)
        editTextList = new ArrayList<EditText>();

    int childCount = viewgroup.getChildCount();
    for(int i=0; i<= childCount-1;i++) 
    {
        View v = viewgroup.getChildAt(i);

        if(v instanceof ViewGroup) 
        {
            initEditTexts((ViewGroup) v);
        }

        if(v instanceof EditText) 
        {
            EditText editText = (EditText) v;
            editText.setOnFocusChangeListener(this);
            editText.setCursorVisible(true);
            editTextList.add(editText);
        }
    }
}

/*
 * OnFocusChange does update tempView correctly now when keyboard is still shown
 * Thanks to Israel Dominguez ([email protected])
 */
@Override
public void onFocusChange(View v, boolean hasFocus) 
{
    if(hasFocus) 
    {
        tempView = v;
        if(!isKeyboardShow) 
        {
            layoutBottom = getLayoutCoordinates();
            softKeyboardThread.keyboardOpened();
            isKeyboardShow = true;
        }
    }
}

// This handler will clear focus of selected EditText
private final Handler mHandler = new Handler()
{
    @Override
    public void handleMessage(Message m)
    {
        switch(m.what)
        {
        case CLEAR_FOCUS:
            if(tempView != null)
            {
                tempView.clearFocus();
                tempView = null;
            }
            break;
        }
    }
};

private class SoftKeyboardChangesThread extends Thread
{
    private AtomicBoolean started;
    private SoftKeyboardChanged mCallback;

    public SoftKeyboardChangesThread()
    {
        started = new AtomicBoolean(true);
    }

    public void setCallback(SoftKeyboardChanged mCallback)
    {
        this.mCallback = mCallback;
    }

    @Override
    public void run()
    {
        while(started.get())
        {
            // Wait until keyboard is requested to open
            synchronized(this)
            {
                try 
                {
                    wait();
                } catch (InterruptedException e) 
                {
                    e.printStackTrace();
                }
            }

            int currentBottomLocation = getLayoutCoordinates();

            // There is some lag between open soft-keyboard function and when it really appears.
            while(currentBottomLocation == layoutBottom && started.get())
            {
                currentBottomLocation = getLayoutCoordinates();
            }

            if(started.get())
                mCallback.onSoftKeyboardShow();

            // When keyboard is opened from EditText, initial bottom location is greater than layoutBottom
            // and at some moment equals layoutBottom.
            // That broke the previous logic, so I added this new loop to handle this.
            while(currentBottomLocation >= layoutBottom && started.get())
            {
                currentBottomLocation = getLayoutCoordinates();
            }

            // Now Keyboard is shown, keep checking layout dimensions until keyboard is gone
            while(currentBottomLocation != layoutBottom && started.get())
            {
                                    synchronized(this)
                {
                    try 
                    {
                        wait(500);
                    } catch (InterruptedException e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                currentBottomLocation = getLayoutCoordinates();
            }

            if(started.get())
                mCallback.onSoftKeyboardHide();

            // if keyboard has been opened clicking and EditText.
            if(isKeyboardShow && started.get())
                isKeyboardShow = false;

            // if an EditText is focused, remove its focus (on UI thread)
            if(started.get())
                mHandler.obtainMessage(CLEAR_FOCUS).sendToTarget();
        }   
    }

    public void keyboardOpened()
    {
        synchronized(this)
        {
            notify();
        }
    }

    public void stopThread()
    {
        synchronized(this)
        {
            started.set(false);
            notify();
        }
    }

}
}

В Android Manifest необходимо android:windowSoftInputMode="adjustResize".

/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root
InputMethodManager im = (InputMethodManager)getSystemService(Service.INPUT_METHOD_SERVICE);

/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged() {

@Override
public void onSoftKeyboardHide()  {
    // Code here
}

@Override
public void onSoftKeyboardShow() {
    // Code here
}   
});

/*
Open or close the soft keyboard easily
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();

/* Prevent memory leaks:*/
@Override
public void onDestroy() {
    super.onDestroy();
    softKeyboard.unRegisterSoftKeyboardCallback();
}

P.S - Полностью взято из здесь.

person Shubham A.    schedule 26.10.2015

В случае adjustResize и FragmentActivity принятое решение от @Jaap у меня не работает.

Вот мое решение:

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    private int contentDiff;
    private int rootHeight;
    @Override
    public void onGlobalLayout() {
        View contentView = getWindow().findViewById(Window.ID_ANDROID_CONTENT);
        if (rootHeight != mDrawerLayout.getRootView().getHeight()) {
            rootHeight = mDrawerLayout.getRootView().getHeight();
            contentDiff = rootHeight - contentView.getHeight();
            return;
        }
        int newContentDiff = rootHeight - contentView.getHeight();
        if (contentDiff != newContentDiff) {
            if (contentDiff < newContentDiff) {
                onShowKeyboard(newContentDiff - contentDiff);
            } else {
                onHideKeyboard();
            }
            contentDiff = newContentDiff;
        }
    }
};
person AnoDest    schedule 23.03.2017

Другой подход - проверить, когда пользователь перестал печатать ...

Когда TextEdit находится в фокусе (пользователь набирает / набирает), вы можете скрыть представления (прослушиватель фокуса)

и используйте Handler + Runnable и прослушиватель изменения текста, чтобы закрыть клавиатуру (независимо от ее видимости) и отобразить представления после некоторой задержки.

Главное, на что следует обратить внимание, - это используемая вами задержка, которая будет зависеть от содержимого этих TextEdits.

Handler timeoutHandler = new Handler();
Runnable typingRunnable = new Runnable() {
    public void run() {
        // current TextEdit
        View view = getCurrentFocus();

        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        // reset focus
        view.clearFocus();
        // close keyboard (whether its open or not)
        imm.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);

        // SET VIEWS VISIBLE
    }
};

editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            // SET VIEWS GONE

            // reset handler
            timeoutHandler.removeCallbacks(typingRunnable);
            timeoutHandler.postDelayed(typingRunnable, TYPING_TIMEOUT);
        }
    }
});

editText.addTextChangedListener(new TextWatcher() {
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // Reset Handler...
        timeoutHandler.removeCallbacks(typingRunnable);
    }

    @Override
    public void afterTextChanged(Editable s) {
        // Reset Handler Cont.
        if (editText.getText().toString().trim().length() > 0) {
            timeoutHandler.postDelayed(typingRunnable, TYPING_TIMEOUT);
        }
    }
});
person Ullauri    schedule 14.10.2017

Этот код отлично работает

используйте этот класс для корневого просмотра:

public class KeyboardConstraintLayout extends ConstraintLayout {

private KeyboardListener keyboardListener;
private EditText targetEditText;
private int minKeyboardHeight;
private boolean isShow;

public KeyboardConstraintLayout(Context context) {
    super(context);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); //128dp
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); // 128dp
}

public KeyboardConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height); // 128dp
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (!isInEditMode()) {
        Activity activity = (Activity) getContext();
        @SuppressLint("DrawAllocation")
        Rect rect = new Rect();
        getWindowVisibleDisplayFrame(rect);

        int statusBarHeight = rect.top;
        int keyboardHeight = activity.getWindowManager().getDefaultDisplay().getHeight() - (rect.bottom - rect.top) - statusBarHeight;

        if (keyboardListener != null && targetEditText != null && targetEditText.isFocused()) {
            if (keyboardHeight > minKeyboardHeight) {
                if (!isShow) {
                    isShow = true;
                    keyboardListener.onKeyboardVisibility(true);
                }
            }else {
                if (isShow) {
                    isShow = false;
                    keyboardListener.onKeyboardVisibility(false);
                }
            }
        }
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

public boolean isShowKeyboard() {
    return isShow;
}

public void setKeyboardListener(EditText targetEditText, KeyboardListener keyboardListener) {
    this.targetEditText = targetEditText;
    this.keyboardListener = keyboardListener;
}

public interface KeyboardListener {
    void onKeyboardVisibility (boolean isVisible);
}

}

и установите прослушиватель клавиатуры в действии или фрагменте:

        rootLayout.setKeyboardListener(targetEditText, new KeyboardConstraintLayout.KeyboardListener() {
        @Override
        public void onKeyboardVisibility(boolean isVisible) {

        }
    });
person saleh gholamian    schedule 22.05.2018

Вы можете управлять видимостью клавиатуры, переопределив два метода в своем Activity: onKeyUp() и onKeyDown() дополнительную информацию в этой ссылке: https://developer.android.com/training/keyboard-input/commands

person Arthur Arzumanyan    schedule 25.07.2019
comment
В документации точно указано, что эти функции не должны использоваться в отношении мягкой клавиатуры ввода. - person Piotr Prus; 25.05.2020

К сожалению, у меня нет достаточно высокой репутации, чтобы комментировать ответ Яапа ван Хенгстума. Но я прочитал несколько комментариев людей, у которых возникла проблема, что contentViewTop всегда 0 и что onShowKeyboard(...) всегда вызывается.

У меня была такая же проблема, и я понял, в чем проблема. Я использовал AppCompatActivity вместо «нормального» Activity. В этом случае Window.ID_ANDROID_CONTENT относится к ContentFrameLayout, а не к FrameLayout с правым верхним значением. В моем случае было нормально использовать «нормальный» Activity, если вам нужно использовать другой тип активности (я только что протестировал AppCompatActivity, возможно, это также проблема с другими типами активности, такими как FragmentActivity), вам нужно получить доступ к FrameLayout, который является предком ContentFrameLayout.

person agi    schedule 06.03.2016

когда клавиатура показывает

rootLayout.getHeight() < rootLayout.getRootView().getHeight() - getStatusBarHeight() 

правда, иначе скрыть

person 余艳辉    schedule 23.03.2017

private boolean isKeyboardShown = false;
private int prevContentHeight = 0;
private ViewGroup contentLayout;

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener =
        new ViewTreeObserver.OnGlobalLayoutListener() {

    @Override
    public void onGlobalLayout() {
        int contentHeight = contentLayout.getHeight();
        int rootViewHeight = contentLayout.getRootView().getHeight();

        if (contentHeight > 0) {

            if (!isKeyboardShown) {
                if (contentHeight < prevContentHeight) {
                    isKeyboardShown = true;
                    onShowKeyboard(rootViewHeight - contentHeight);
                }
            } else {
                if (contentHeight > prevContentHeight) {
                    isKeyboardShown = false;
                    onHideKeyboard();
                }
            }

            prevContentHeight = contentHeight;
        }
    }
};

Я немного изменил принятый ответ Яапа. Но в моем случае есть несколько предположений, таких как android:windowSoftInputMode=adjustResize, и клавиатура не отображается в начале при запуске приложения. Кроме того, я предполагаю, что экран соответствует высоте родителя.

contentHeight > 0 эта проверка позволяет мне узнать, скрыт или показан соответствующий экран, чтобы применить прослушивание событий клавиатуры для этого конкретного экрана. Также я передаю макет соответствующего экрана в attachKeyboardListeners(<your layout view here>) в методе onCreate() моего основного действия. Каждый раз, когда высота соответствующего экрана изменяется, я сохраняю его в переменной prevContentHeight, чтобы позже проверить, отображается ли клавиатура или скрыта.

Для меня до сих пор это проработано очень хорошо. Я надеюсь, что это сработает и для других.

person psychoplasma    schedule 03.08.2017

Ответ «Яап ван Хенгстум» работает для меня, но нет необходимости устанавливать «android: windowSoftInputMode», как он только что сказал!

Я сделал его меньше (теперь он просто определяет то, что я хочу, на самом деле событие при отображении и скрытии клавиатуры):

private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
        int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
        if(heightDiff <= contentViewTop){
            onHideKeyboard();
        } else {
            onShowKeyboard();
        }
    }
};

private boolean keyboardListenersAttached = false;
private ViewGroup rootLayout;

protected void onShowKeyboard() {}
protected void onHideKeyboard() {}

protected void attachKeyboardListeners() {
    if (keyboardListenersAttached) {
        return;
    }

    rootLayout = (ViewGroup) findViewById(R.id.CommentsActivity);
    rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);

    keyboardListenersAttached = true;
}

@Override
protected void onDestroy() {
    super.onDestroy();

    if (keyboardListenersAttached) {
        rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
    }
}

и просто не забудьте добавить это

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_comments);
    attachKeyboardListeners();}
person Khalil Al-rahman Yossefi    schedule 20.01.2018

Это не работает так, как хотелось бы ...

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

Я хотел определить, открыт он или нет, и Я обнаружил _ 1_

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

в деятельности

    if (((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
    } else {
        Log.d(TAG,"Software Keyboard was not shown");
    }

во фрагменте

    if (((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)).isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
    } else {
        Log.d(TAG,"Software Keyboard was not shown");

    }
person Community    schedule 08.10.2018

проверьте с помощью приведенного ниже кода:

КОД XML:

<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorParent"
    style="@style/parentLayoutPaddingStyle"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  .................


</android.support.constraint.ConstraintLayout>

КОД JAVA:

//Global Variable
android.support.constraint.ConstraintLayout activityRootView;
boolean isKeyboardShowing = false;
private  ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener;
android.support.constraint.ConstraintLayout.LayoutParams layoutParams;




 //onCreate or onViewAttached
    activityRootView = view.findViewById(R.id.coordinatorParent);
        onGlobalLayoutListener = onGlobalLayoutListener();
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);


  //outside oncreate
  ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener() {
        return new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                activityRootView.getWindowVisibleDisplayFrame(r);
                int screenHeight = activityRootView.getRootView().getHeight();
                int keypadHeight = screenHeight - r.bottom;

                if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
                    if (!isKeyboardShowing) {  // keyboard is opened
                        isKeyboardShowing = true;
                        onKeyboardVisibilityChanged(true);
                   }
                }
                else {
                    if (isKeyboardShowing) {   // keyboard is closed
                        isKeyboardShowing = false;
                        onKeyboardVisibilityChanged(false);
                    }
                }
            }//ends here
        };

    }


    void onKeyboardVisibilityChanged(boolean value) {
        layoutParams = (android.support.constraint.ConstraintLayout.LayoutParams)topImg.getLayoutParams();

        if(value){
           int length = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 90, getResources().getDisplayMetrics());
            layoutParams.height= length;
            layoutParams.width = length;
            topImg.setLayoutParams(layoutParams);
            Log.i("keyboard " ,""+ value);
        }else{
            int length1 = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 175, getResources().getDisplayMetrics());
            layoutParams.height= length1;
            layoutParams.width = length1;
            topImg.setLayoutParams(layoutParams);
            Log.i("keyboard " ,""+ value);
        }
    }


    @Override
    public void onDetach() {
        super.onDetach();
        if(onGlobalLayoutListener != null) {
            activityRootView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
        }
    }
person Abhishek kumar    schedule 20.09.2019

Слушатель отклонен с клавиатуры.
Класс SearchEditText является производным от класса android.widget.EditText. В этом классе есть интерфейс SearchEditText.OnKeyboardDismissListener. Вы можете посмотреть документацию:
https://developer.android.com/reference/androidx/leanback/widget/SearchEditText

Примечание. Перед использованием SearchEditText вам необходимо настроить зависимости Gradle в build.gradle (: app):

implementation 'androidx.leanback:leanback:1.1.0-alpha05'

Может кому пригодится.

Подробный ответ:

import androidx.appcompat.app.AppCompatActivity;
import androidx.leanback.widget.SearchEditText;

import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity
        implements SearchEditText.OnKeyboardDismissListener {

    SearchEditText searchEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        searchEditText = findViewById(R.id.search_edit_text);

        searchEditText.setOnKeyboardDismissListener(this);
    }

    /**
     * Method invoked when the keyboard is dismissed.
     */
    @Override
    public void onKeyboardDismiss() {
        Toast.makeText(this, "The listener worked", Toast.LENGTH_LONG).show();
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.leanback.widget.SearchEditText
        android:id="@+id/search_edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:textSize="20sp"
        android:focusableInTouchMode="true"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Примечание: слушатель работает с:

android:windowSoftInputMode="adjustPan"
android:windowSoftInputMode="adjustResize"
person Justin Case    schedule 04.10.2020
comment
Я реализую это в MainActivity, и в пользовательском интерфейсе есть только один editText, но он не вызывается при отклонении клавиатуры. - person Asad Mukhtar; 16.10.2020
comment
@AsadMukhtar Привет, посмотрите мой подробный ответ выше. Надеюсь, это поможет. - person Justin Case; 17.10.2020

Обнаружен точный способ узнать, используется ли клавиатура при использовании режима мягкого ввода AdjustResize (код Kotlin)

Определите пару переменных области действия

private var activityHeight = 0
private var keyboardOpen = false

Напишите следующий код в onCreate

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        ...

        /* Grab initial screen value */
        [email protected] {
            val displayFrame : Rect = Rect()
            [email protected](displayFrame)
            activityHeight = displayFrame.height()
        }

        /* Check for keyboard open/close */
        [email protected] { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
            val drawFrame : Rect = Rect()
            [email protected](drawFrame)
            val currentSize = drawFrame.height()

            keyboardOpen = currentSize < activityHeight
            Log.v("keyboard1","$keyboardOpen $currentSize - $activityHeight")
        }
}

Теперь у вас есть логическое значение, которое точно отслеживает, открыта клавиатура или нет, делайте то, что хотите

person Rowan Berry    schedule 01.12.2020

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/addresses_confirm_root_view"
android:orientation="vertical">

‹--- В корне xml используйте id ---›

последнее действие LinearLayoutRootView = view.findViewById (R.id.addresses_confirm_root_view); activityRootView.getViewTreeObserver (). addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener () {@Override public void onGlobalLayout () {Rect r = new Rect (); // r будет заполнен координатами вашего viewRoot, эта область все еще видна. getWindowVisibleDisplayFrame (r);

            int heightDiff = activityRootView.getRootView().getHeight() - r.height();
            if (heightDiff > 0.25 * activityRootView.getRootView().getHeight()) {
                // if more than 25% of the screen, its probably a keyboard...
                onkeyboard();

            } else {
                //Keyboard not visible
                offkeyboard();
            }
        }
    });
person MANOJ G    schedule 06.02.2021

Я создал слушателя, используя этот ответ и мою задачу LoopingTask, кстати, спасибо.

Очень легко реализовать с помощью SoftKeyboardListener из библиотеки Android Viper Pack.

Просто установите библиотеку и добавьте это в свой код:

Lava.app.addSoftKeyboardListener(context, new Lava.SoftKeyboardListener() {
@Override
public void onSoftKeyboardShow(EditText focusedview) {
// when shows
}
@Override
public void onSoftKeyboardHide(EditText focusedview) {
// when hides
}
});
Dislaimer : adding a lot of listeners may slow/crash your app, you still can use Lava.app.removeSoftKeyboardListeners() to remove all the previous listeners. Dislaimer 2 : creating a SoftKeyboardListener directly in activity onCreate will add a new one every time the activity resume itself, so make sure to limit that using a boolean :
boolean isListenerAdded;
...
@Override
public void onCreate(Bundle sis) {
super.onCreate(sis);
...
if (!isListenerAdded) {
isListenerAdded = true;
// create your listener here
}
...
}
...

Или просто удалите все предыдущие:

...
@Override
public void onCreate(Bundle sis) {
super.onCreate(sis);
...
Lava.app.removeSoftKeyboardListeners();
// create your listener here
...
}
...

Lava.app.removeSoftKeyboardListeners() удаляет все предыдущие прослушиватели SoftKeyboardListeners.

person Viper    schedule 24.03.2021
comment
Привет ... Осматриваем // Смотрим ... Ваш ответ плохо продуман. Полезно вставить эффективный ответ с кодами и ссылками. Вывод практичного и эффективного решения. Эта площадка - не просто форум. Мы являемся крупнейшим центром помощи и поддержки для других программистов и разработчиков в мире. Ознакомьтесь с условиями сообщества и узнайте, как публиковать сообщения; - person Paulo Boaventura; 24.03.2021

Проверьте мое расширение Kotlin View.keyboardVisibilityChanges():

fun View.keyboardVisibilityChanges(): Flow<Boolean>{
    return onPreDrawFlow()
        .map { isKeyboardVisible() }
        .distinctUntilChanged()
}
fun View.onPreDrawFlow(): Flow<Unit> {
    return callbackFlow {
        val onPreDrawListener = ViewTreeObserver.OnPreDrawListener {
            trySendBlocking(Unit)
            true
        }
        viewTreeObserver.addOnPreDrawListener(onPreDrawListener)
        awaitClose {
            viewTreeObserver.removeOnPreDrawListener(onPreDrawListener)
        }
    }
}
fun View.isKeyboardVisible(): Boolean = ViewCompat.getRootWindowInsets(this)
    ?.isVisible(Type.ime())
    ?: false
person Vlad    schedule 23.05.2021

сначала создайте файл kotlin и добавьте эти методы:

fun Activity.getRootView(): View {
    return findViewById<View>(android.R.id.content)
}
fun Context.convertDpToPx(dp: Float): Float {
    return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 
            dp, 
            this.resources.displayMetrics
    )
}
fun Activity.isKeyboardOpen(): Boolean {
    val visibleBounds = Rect()
    this.getRootView().getWindowVisibleDisplayFrame(visibleBounds)
    val heightDiff = getRootView().height - visibleBounds.height()
    val marginOfError = Math.round(this.convertDpToPx(50F))
    return heightDiff > marginOfError
}

fun Activity.isKeyboardClosed(): Boolean {
    return !this.isKeyboardOpen()
}

затем создайте класс слушателя для проверки того, открыта клавиатура или нет:

class KeyboardEventListener(
        private val activity: AppCompatActivity,
        private val callback: (isOpen: Boolean) -> Unit
) : LifecycleObserver {
     private val listener = object : ViewTreeObserver.OnGlobalLayoutListener {
     private var lastState: Boolean = activity.isKeyboardOpen()
      override fun onGlobalLayout() {
            val isOpen = activity.isKeyboardOpen()
            if (isOpen == lastState) {
                return
            } else {
                dispatchKeyboardEvent(isOpen)
                lastState = isOpen
            }
        }
    }
    init {
        // Dispatch the current state of the keyboard
        dispatchKeyboardEvent(activity.isKeyboardOpen())
        // Make the component lifecycle aware
        activity.lifecycle.addObserver(this)
        registerKeyboardListener()
    }
    private fun registerKeyboardListener() {
        activity.getRootView().viewTreeObserver.addOnGlobalLayoutListener(listener)
    }
    private fun dispatchKeyboardEvent(isOpen: Boolean) {
        when {
            isOpen  -> callback(true)
            !isOpen -> callback(false)
        }
    }
    @OnLifecycleEvent(value = Lifecycle.Event.ON_PAUSE)
    @CallSuper
    fun onLifecyclePause() {
        unregisterKeyboardListener()
    }
    private fun unregisterKeyboardListener() {
        activity.getRootView().viewTreeObserver.removeOnGlobalLayoutListener(listener)
    }
}

и используйте это так:

override fun onResume() {
      super.onResume()
      KeyboardEventListener(this) { isOpen -> // handle event }
  }

Надеюсь, вы сочтете это полезным.

person GolnazTorabi    schedule 18.12.2020

Решение с дополнительным свойством в Activity \ Fragment, но без каких-либо гипотетических жестко заданных значений высоты (например, 100 и т. Д.). Просто добавьте OnGlobalLayoutListener в корневое представление и сохраните его начальную высоту до отображения клавиатуры:

var firstLoad         = true
var contentFullWeight = 0

override fun onViewCreated(layoutView: View, savedInstanceState: Bundle?) {
    super.onViewCreated(layoutView, savedInstanceState)

    view?.viewTreeObserver?.addOnGlobalLayoutListener(ViewTreeObserver.OnGlobalLayoutListener {

        if(firstLoad){
            contentFullWeight = view?.height!!
            firstLoad = false
        }

        if (view?.height!! < contentFullWeight) {
            Log.d("TEZT_KEYBOARD", ">> KBD OPENED")
        } else {
            Log.d("TEZT_KEYBOARD", ">> KBD closed")
        }
    })

}
person chatlanin    schedule 24.12.2020

person    schedule
comment
Предположим, я нажимаю на edittext, тогда он setOnFocusChangeListener listener будет вызываться, затем я нажимаю обратно, он закрывает клавиатуру, но не нажимаю на другие представления, теперь я снова нажимаю на тот же edittext, который уже имеет фокус, тогда что произойдет? - person N Sharma; 12.09.2014
comment
это не мой вопрос. Пожалуйста, прочтите мой вопрос еще раз - у меня есть Activity, где есть 5 EditText. Когда пользователь нажимает первый EditText, затем открывается мягкая клавиатура, чтобы ввести в него какое-то значение. Я хочу установить для некоторой другой видимости View значение Gone, когда мягкая клавиатура открывается, когда пользователь нажимает на первый EditText и когда мягкая клавиатура закрывается из того же EditText при обратном нажатии, тогда я хочу установить видимость другого View видимости. Есть ли какой-либо слушатель, обратный вызов или какой-либо взлом, когда мягкая клавиатура открывается при нажатии на первый EditText в Android? - person N Sharma; 14.09.2014
comment
Когда вы нажимаете назад, он закрывает клавиатуру, когда onfocus слушатель никогда не звонит, это то, что я ищу, а не то, что вы предлагаете - person N Sharma; 14.09.2014