Как определить, отображается ли программная клавиатура на устройстве Android?

Есть ли способ в Android обнаружить, что клавиатура программного обеспечения (a.k.a. "soft" ) видна на экране?

Ответ 2

Это работает для меня. Может быть, это всегда лучший способ для всех версий.

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

boolean isKeyboardShowing = false;
void onKeyboardVisibilityChanged(boolean opened) {
    print("keyboard " + opened);
}

// ContentView is the root view of the layout of this activity/fragment    
contentView.getViewTreeObserver().addOnGlobalLayoutListener(
    new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {

        Rect r = new Rect();
        contentView.getWindowVisibleDisplayFrame(r);
        int screenHeight = contentView.getRootView().getHeight();

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        int keypadHeight = screenHeight - r.bottom;

        Log.d(TAG, "keypadHeight = " + keypadHeight);

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

Ответ 3

попробуйте следующее:

InputMethodManager imm = (InputMethodManager) getActivity()
            .getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        writeToLog("Software Keyboard was shown");
    } else {
        writeToLog("Software Keyboard was not shown");
    }

Ответ 4

Я создал простой класс, который можно использовать для этого: https://github.com/ravindu1024/android-keyboardlistener. Просто скопируйте его в свой проект и используйте следующим образом:

KeyboardUtils.addKeyboardToggleListener(this, new KeyboardUtils.SoftKeyboardToggleListener()
{
    @Override
    public void onToggleSoftKeyboard(boolean isVisible)
    {
        Log.d("keyboard", "keyboard visible: "+isVisible);
    }
});

Ответ 5

Очень просто

1. Поместите идентификатор на ваш корневой вид

rootView - это просто представление, указывающее на мое корневое представление, в данном случае relative layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/addresses_confirm_root_view"
                android:background="@color/WHITE_CLR">

2. Инициализируйте свое корневое представление в своей деятельности:

RelativeLayout rootView = (RelativeLayout) findViewById(R.id.addresses_confirm_root_view);

3. Определите, открыта или закрыта клавиатура, используя getViewTreeObserver()

    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();

                if (heightDiff > 100) { 
                    Log.e("MyActivity", "keyboard opened");
                } else { 
                    Log.e("MyActivity", "keyboard closed");
                }
            }
        });

Ответ 7

Я использовал это в качестве основы: http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android

/**
* To capture the result of IMM hide/show soft keyboard
*/
public class IMMResult extends ResultReceiver {
     public int result = -1;
     public IMMResult() {
         super(null);
}

@Override 
public void onReceiveResult(int r, Bundle data) {
    result = r;
}

// poll result value for up to 500 milliseconds
public int getResult() {
    try {
        int sleep = 0;
        while (result == -1 && sleep < 500) {
            Thread.sleep(100);
            sleep += 100;
        }
    } catch (InterruptedException e) {
        Log.e("IMMResult", e.getMessage());
    }
    return result;
}
}

Затем написал этот метод:

public boolean isSoftKeyboardShown(InputMethodManager imm, View v) {

    IMMResult result = new IMMResult();
    int res;

    imm.showSoftInput(v, 0, result);

    // if keyboard doesn't change, handle the keypress
    res = result.getResult();
    if (res == InputMethodManager.RESULT_UNCHANGED_SHOWN ||
            res == InputMethodManager.RESULT_UNCHANGED_HIDDEN) {

        return true;
    }
    else
        return false;

}

Затем вы можете использовать это для проверки всех полей (EditText, AutoCompleteTextView и т.д.), которые могли открыть программную клавиатуру:

    InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    if(isSoftKeyboardShown(imm, editText1) | isSoftKeyboardShown(imm, autocompletetextview1))
        //close the softkeyboard
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);

Довольно не идеальное решение, но оно выполняет свою работу.

Ответ 8

Вы можете обратиться к этому ответу - fooobar.com/questions/16599/...

Он работал у меня каждый раз.

adb shell dumpsys window InputMethod | grep "mHasSurface"

Он вернет true, если видна программная клавиатура.

Ответ 9

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

В MainActivity:

public void dismissKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.hideSoftInputFromWindow(mSearchBox.getWindowToken(), 0);
    mKeyboardStatus = false;
}

public void showKeyboard(){
    InputMethodManager imm =(InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
    imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    mKeyboardStatus = true;
}

private boolean isKeyboardActive(){
    return mKeyboardStatus;
}

Предполагаемое логическое значение по умолчанию для mKeyboardStatus будет инициализировано до false.

Затем проверьте значение следующим образом и при необходимости выполните действие:

 mSearchBox.requestFocus();
    if(!isKeyboardActive()){
        showKeyboard();
    }else{
        dismissKeyboard();
    }

Ответ 10

Я сделал это, установив GlobalLayoutListener следующим образом:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
        new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                int heightView = activityRootView.getHeight();
                int widthView = activityRootView.getWidth();
                if (1.0 * widthView / heightView > 3) {
                    //Make changes for Keyboard not visible
                } else {
                    //Make changes for keyboard visible
                }
            }
        });

Ответ 11

Попробуйте этот код, который действительно работает, если отображается KeyboardShown, тогда эта функция возвращает истинное значение....

private final String TAG = "TextEditor";
private TextView mTextEditor;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_editor);
    mTextEditor = (TextView) findViewById(R.id.text_editor);
    mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            isKeyboardShown(mTextEditor.getRootView());
        }
    });
}

private boolean isKeyboardShown(View rootView) {
    /* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
    final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;

    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    /* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
    int heightDiff = rootView.getBottom() - r.bottom;
    /* Threshold size: dp to pixels, multiply with display density */
    boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;

    Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
            + "root view height:" + rootView.getHeight() + ", rect:" + r);

    return isKeyboardShown;
}

Ответ 12

В моем случае у меня был только один EditText для управления в моем макете, поэтому я подошел к whit это решение. Он хорошо работает, в основном это пользовательский EditText, который прослушивает фокус и отправляет локальную широковещательную рассылку, если фокус меняется или нажата кнопка "Назад/Готово". Для работы вам нужно разместить макет View в вашем макете с помощью android:focusable="true" и android:focusableInTouchMode="true", потому что, когда вы вызываете clearFocus(), фокус будет переназначен в первый настраиваемый вид. Пример фиктивного представления:

<View
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"/>

Дополнительная информация

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

Ответ 13

Так что после долгого времени игры с AccessibilityServices, оконными вставками, определением высоты экрана и т.д., Я думаю, я нашел способ сделать это.

Отказ от ответственности: он использует скрытый метод в Android, что означает, что он может быть непоследовательным. Тем не менее, в моем тестировании, похоже, работает.

Этот метод является InputMethodManager # getInputMethodWindowVisibleHeight() и существует с Lollipop (5.0).

Вызов, который возвращает высоту в пикселях текущей клавиатуры. Теоретически клавиатура не должна быть 0 пикселей в высоту, поэтому я сделал простую проверку высоты (в Kotlin):

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
if (imm.inputMethodWindowVisibleHeight > 0) {
    //keyboard is shown
else {
    //keyboard is hidden
}

Я использую Android Hidden API, чтобы избежать рефлексии, когда я вызываю скрытые методы (я делаю это много для приложений, которые я разрабатываю, в основном это хакерские/настраивающие приложения), но это должно быть возможно и с помощью рефлексии:

val imm by lazy { context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager }
val windowHeightMethod = InputMethodManager::class.java.getMethod("getInputMethodWindowVisibleHeight")
val height = windowHeightMethod.invoke(imm) as Int
//use the height val in your logic

Ответ 14

Это должно работать, если вам нужно проверить состояние клавиатуры:

fun Activity.isKeyboardOpened(): Boolean {
    val r = Rect()

    val activityRoot = getActivityRoot()
    val visibleThreshold = dip(UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP)

    activityRoot.getWindowVisibleDisplayFrame(r)

    val heightDiff = activityRoot.rootView.height - r.height()

    return heightDiff > visibleThreshold;
}

fun Activity.getActivityRoot(): View {
    return (findViewById<ViewGroup>(android.R.id.content)).getChildAt(0);
}

Где UiUtils.KEYBOARD_VISIBLE_THRESHOLD_DP= 100 и dip() - это функция anko, которая преобразует dpToPx:

fun dip(value: Int): Int {
    return (value * Resources.getSystem().displayMetrics.density).toInt()
}

Ответ 15

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

            Rect r = new Rect();
            activityRootView.getWindowVisibleDisplayFrame(r);

            int screenHeight = activityRootView.getRootView().getHeight();
            Log.e("screenHeight", String.valueOf(screenHeight));
            int heightDiff = screenHeight - (r.bottom - r.top);
            Log.e("heightDiff", String.valueOf(heightDiff));
            boolean visible = heightDiff > screenHeight / 3;
            Log.e("visible", String.valueOf(visible));
            if (visible) {
                Toast.makeText(LabRegister.this, "I am here 1", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(LabRegister.this, "I am here 2", Toast.LENGTH_SHORT).show();
            }
        }
});

Ответ 16

Ответа на этот вопрос @iWantScala отлично, но не работает для меня
rootView.getRootView().getHeight() всегда имеет такое же значение

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

private int maxRootViewHeight = 0;
private int currentRootViewHeight = 0;

добавить глобальный прослушиватель

rootView.getViewTreeObserver()
    .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            currentRootViewHeight = rootView.getHeight();
            if (currentRootViewHeight > maxRootViewHeight) {
                maxRootViewHeight = currentRootViewHeight;
            }
        }
    });

затем проверьте

if (currentRootViewHeight >= maxRootViewHeight) {
    // Keyboard is hidden
} else {
    // Keyboard is shown
}

отлично работает

Ответ 17

У меня была аналогичная проблема. Мне нужно было реагировать на кнопку Enter на экране (которая скрывала клавиатуру). В этом случае вы можете подписаться на OnEditorAction текстового представления, с которым была открыта клавиатура - если у вас есть несколько редактируемых блоков, а затем подписаться на все из них.

В вашей деятельности у вас есть полный контроль над клавиатурой, поэтому ни при каких обстоятельствах вы не столкнетесь с проблемой, открыта ли клавиатура или нет, если вы слушаете все события открытия и закрытия.

Ответ 18

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

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

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

Нижеприведенная реализация выполняет только одну проверку.
Если вы выполняете несколько проверок, вы должны включить все тесты (_keyboardVisible).

public interface OnKeyboardShowHide
{
    void    onShowKeyboard( Object param );
    void    onHideKeyboard( Object param );
}

private static Handler      _keyboardHandler    = new Handler();
private boolean             _keyboardVisible    = false;
private OnKeyboardShowHide  _keyboardCallback;
private Object              _keyboardCallbackParam;

public void start( OnKeyboardShowHide callback, Object callbackParam )
{
    _keyboardCallback      = callback;
    _keyboardCallbackParam = callbackParam;
    //
    View view = getCurrentFocus();
    if (view != null)
    {
        InputMethodManager imm = (InputMethodManager) getSystemService( Activity.INPUT_METHOD_SERVICE );
        imm.hideSoftInputFromWindow( view.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY, _keyboardResultReceiver );
        imm.showSoftInput( view, InputMethodManager.SHOW_IMPLICIT, _keyboardResultReceiver );
    }
    else // if (_keyboardVisible)
    {
        _keyboardVisible = false;
        _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
    }
}

private ResultReceiver      _keyboardResultReceiver = new ResultReceiver( _keyboardHandler )
{
    @Override
    protected void onReceiveResult( int resultCode, Bundle resultData )
    {
        switch (resultCode)
        {
            case InputMethodManager.RESULT_SHOWN :
            case InputMethodManager.RESULT_UNCHANGED_SHOWN :
                // if (!_keyboardVisible)
                {
                    _keyboardVisible = true;
                    _keyboardCallback.onShowKeyboard( _keyboardCallbackParam );
                }
                break;
            case InputMethodManager.RESULT_HIDDEN :
            case InputMethodManager.RESULT_UNCHANGED_HIDDEN :
                // if (_keyboardVisible)
                {
                    _keyboardVisible = false;
                    _keyboardCallback.onHideKeyboard( _keyboardCallbackParam );
                }
                break;
        }
    }
};

Ответ 19

В Android вы можете обнаружить через оболочку ADB. Я написал и использовал этот метод:

{
        JSch jsch = new JSch();
        try {
            Session session = jsch.getSession("<userName>", "<IP>", 22);
            session.setPassword("<Password>");
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect();

            ChannelExec channel = (ChannelExec)session.openChannel("exec");
            BufferedReader in = new BufferedReader(new    
            InputStreamReader(channel.getInputStream()));
            channel.setCommand("C:/Android/android-sdk/platform-tools/adb shell dumpsys window 
            InputMethod | findstr \"mHasSurface\"");
            channel.connect();

            String msg = null;
            String msg2 = " mHasSurface=true";

            while ((msg = in.readLine()) != null) {
                Boolean isContain = msg.contains(msg2);
                log.info(isContain);
                if (isContain){
                    log.info("Hiding keyboard...");
                    driver.hideKeyboard();
                }
                else {
                    log.info("No need to hide keyboard.");
                }
            }

            channel.disconnect();
            session.disconnect();

        } catch (JSchException | IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Ответ 20

Ниже приведено обходное решение, чтобы узнать, видна ли клавиатура.

  • Проверить работу запущенных служб в системе с помощью ActivityManager.getRunningServices(max_count_of_services);
  • В возвращаемых экземплярах ActivityManager.RunningServiceInfo установите флажок clientCount для обслуживания мягкой клавиатуры.
  • Вышеупомянутый clientCount будет увеличиваться каждый раз, отображается мягкая клавиатура. Например, если clientCount изначально был 1, это было бы 2, когда будет показана клавиатура.
  • При отмене клавиатуры клиентский счет уменьшается. В этом случае он сбрасывается до 1.

Некоторые из популярных клавиатур имеют определенные ключевые слова в именах классов:

  • Google AOSP = IME
  • Swype = IME
  • Swiftkey = KeyboardService
  • Fleksy = клавиатура
  • Adaptxt = IME (KPTAdaptxtIME)
  • Smart = клавиатура (SmartKeyboard)

Из ActivityManager.RunningServiceInfo проверьте приведенные выше шаблоны в ClassNames. Кроме того, ActivityManager.RunningServiceInfo clientPackage= android, указывая, что клавиатура привязана к системе.

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

Ответ 21

Я думаю, что это старый вопрос, но сегодня я столкнулся с хорошей библиотекой, чтобы определить, что клавиатура открыта ИЛИ нет. Поэтому я делюсь с вами.

У меня была аналогичная проблема, и я нашел для нее одну библиотеку, и я играл с ней. Он работает как аспект. Здесь Клавиатурная библиотека.

Ответ 22

Как вы, наверное, знаете, Клавиатура Android Software будет видна только при возможном событии набора текста. Другими словами, клавиатура становится видимой только тогда, когда находится EditText. это означает, что вы можете узнать, видна клавиатура или нет, с помощью OnFocusChangeListener.

//Declare this Globally

public boolean isKeyBoardVisible = false;

//In OnCreate *[For Activity]*, OnCreateView *[For Fragment]*

text_send.setOnFocusChangeListener(new View.OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus)
            isKeyBoardVisible = true;
        else
            isKeyBoardVisible = false;
    }
});

Теперь вы можете использовать переменную isKeyBoardVisible в любом месте класса, чтобы узнать, открыта ли клавиатура или нет. Это хорошо сработало для меня.

Примечание: этот процесс не работает, когда клавиатура открывается программно с помощью InputMethodManager, потому что это не вызывает OnFocusChangeListener.

Ответ 23

Я преобразовал ответ в kotlin, надеюсь, это поможет пользователям kotlin.

private fun checkKeyboardVisibility() {
    var isKeyboardShowing = false

    binding.coordinator.viewTreeObserver.addOnGlobalLayoutListener {
        val r = Rect()
        binding.coordinator.getWindowVisibleDisplayFrame(r)
        val screenHeight = binding.coordinator.rootView.height

        // r.bottom is the position above soft keypad or device button.
        // if keypad is shown, the r.bottom is smaller than that before.
        val keypadHeight = screenHeight - r.bottom


        if (keypadHeight > screenHeight * 0.15) { // 0.15 ratio is perhaps enough to determine keypad height.
            // keyboard is opened
            if (!isKeyboardShowing) {
                isKeyboardShowing = true

            }
        } else {
            // keyboard is closed
            if (isKeyboardShowing) {
                isKeyboardShowing = false

            }
        }
    }
}

Ответ 24

Я сделал это следующим образом, но его значение можно использовать только в том случае, если ваша цель - закрыть/открыть keyboad.

закрыть пример: (проверка, если клавиатура уже закрыта, если нет - закрытие)

imm.showSoftInput(etSearch, InputMethodManager.HIDE_IMPLICIT_ONLY, new ResultReceiver(null) {
                    @Override
                    protected void onReceiveResult(int resultCode, Bundle resultData) {
                        super.onReceiveResult(resultCode, resultData);
                        if (resultCode != InputMethodManager.RESULT_UNCHANGED_HIDDEN)
                            imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
                    }
                });

Ответ 25

a может использоваться:

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    Log.d(
    getClass().getSimpleName(), 
    String.format("conf: %s", newConfig));

    if (newConfig.hardKeyboardHidden != hardKeyboardHidden) {
        onHardwareKeyboardChange(newConfig.hardKeyboardHidden);

        hardKeyboardHidden = newConfig.hardKeyboardHidden;
    }

    if (newConfig.keyboardHidden != keyboardHidden) {
        onKeyboardChange(newConfig.keyboardHidden);

        keyboardHidden = newConfig.hardKeyboardHidden;
    }

}

public static final int KEYBOARDHIDDEN_UNDEFINED = 0;
public static final int KEYBOARDHIDDEN_NO = 1;
public static final int KEYBOARDHIDDEN_YES = 2;
public static final int KEYBOARDHIDDEN_SOFT = 3;

//todo
private void onKeyboardChange(int keyboardHidden) {

}

//todo
private void onHardwareKeyboardChange(int hardKeyboardHidden) {

}

Ответ 26

Если это поможет мне решить проблему с этим:

 view.findViewById(R.id.main_content).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (keyboardOpen){
                // when keyboard is close do you stuff
                keyboardOpen = false;
            } else {
                keyboardOpen = true;
                // when keyboard is open
            }
        }
    });

клавиатура open - это логическое значение, установленное в true при запуске представления, а id - это идентификатор относительной компоновки в макете

Ответ 27

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

Ответ 28

Может быть что-то вроде этого:

((InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE)).isActive()

Не уверен, но если отображается клавиатура, IMM должен быть установлен на active.