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

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

22 ответов


прямого пути нет-см. http://groups.google.com/group/android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898a где Диана Хакборн из команды Android ответила. Однако вы можете обнаружить его косвенно, проверив, изменился ли размер окна в #onMeasure. См.Как проверить видимость клавиатуры программного обеспечения в Android?.


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

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
    }
    else {
        // keyboard is closed
    }
}
});

попробуйте это:

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

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

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

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

Очень Просто

1. Поместите id в корневое представление

rootView - это просто вид, указывающий на мой корневой вид в этом случае a 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");
                }
            }
        });

вы можете использовать результат обратного вызова showSoftInput () и hideSoftInput (), чтобы проверить состояние клавиатуры. Полная информация и пример кода на

http://www.ninthavenue.com.au/how-to-check-if-the-software-keyboard-is-shown-in-android


вы можете обратиться к этому ответу -https://stackoverflow.com/a/24105062/3629912

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

adb shell dumpsys window InputMethod | grep "mHasSurface"

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


я использовал это в качестве основы: 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 и т. д.), которые могли открыть softkeyboard:

    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);

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


Я сделал это, установив 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
                }
            }
        });

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

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;
}

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

на в 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();
    }

в моем случае у меня был только один EditText для управления в моем макете, поэтому я придумал whit этой решение. Он работает хорошо, в основном это custom 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 может быть много в определенном устройстве и ничего в некоторых других вы можете получить ложные срабатывания. Также разные производители имеют разные клавиатуры.


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

один из способов-определить два vars

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
}

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


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

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


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

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

метод InputMethodManager#getInputMethodWindowVisibleHeight (), и он существует с Lollipop (5.0).

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

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

Я использую Android скрытый 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

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

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


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

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

Остаться в актуальном состоянии вы просто повторяете эту операцию, например каждые 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;
        }
    }
};

в 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();
        }
    }
}

вот обходной путь, чтобы узнать, видна ли softkeyboard.

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

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

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = KeyboardService
  4. Fleksy = клавиатура
  5. Adaptxt = IME (KPTAdaptxtIME)
  6. Smart = Клавиатура (SmartKeyboard)

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

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


Я сделал это следующим образом, но его relevet только если ваша цель-закрыть / открыть 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);
                    }
                });

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();
            }
        }
});

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) {

}