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


250

Есть ли в Android способ определить, видна ли программная («мягкая») клавиатура на экране?



1
что может быть решением этой проблемы в некоторых случаях (если установлена ​​сторонняя клавиатура), чтобы проверить глобальные уведомления, так как когда клавиатура открыта, появляется системное уведомление с надписью «сменить клавиатуру» - это можно сделать с помощью NotificationListenerService
Проф

2
почти 8 лет и до сих пор нет твердого решения, о, если они введут его, оно будет для API> 30 в любом случае, так что не берите в голову ...
M.kazem Akhgary

Ответы:


71

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


276

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

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


1
Поместите это в класс utils и передайте действие - теперь полезно для всего приложения.
Джастин

2
А где contentViewзаявлено?
Ученик

1
@ Code-Apprentice В задании / фрагменте вы хотите отреагировать на изменения софт-клавиатуры. ContentView является корневым представлением макета этого действия / фрагмента.
Airowe

1
Работал для меня на Android 6 и 7.
V.March

71

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

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

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

9
Это не работает для меня. Разветвленная клавиатура срабатывает даже в том случае, когда клавиатура никогда не отображалась или была показана, а затем закрыта.
Питер Айтай

30
это всегда возвращает истину.
Шиванг Триведи

1
Да, это всегда возвращает истину.
Леон Пеллетье

Неправильно. Это всегда возвращает истину
Gaurav Arora

178
Это жалкое , что Android рамка не хватает, и что еще хуже, непоследовательное в этом отношении. Это должно быть очень просто.
Вики Чиджвани

57

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

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

Где в коде точно я должен поставить это? Я включил это в действие, однако он не обнаруживает появление или исчезновение клавиатуры.
Тоум

Ну, вы можете поместить это в любом месте вашей деятельности. Просто поместите его в метод onCreate () после вызова setContentView (), и вы должны получить обратные вызовы. Кстати, на каком устройстве вы его примеряете?
ravindu1024

@MaulikDodia Я проверил, и он отлично работает во фрагментах. Установите его так: KeyboardUtils.addKeyboardToggleListener (getActivity (), this); и это должно работать. На каком устройстве вы это примеряете?
ravindu1024

Я пытаюсь использовать устройство Moto-G3. @ Ravindu1024
Маулик Додиа

Спасибо за этот фрагмент, у меня есть один вопрос, что этот код требуется для удаления слушателя?
Пратик Бутани

28

Очень просто

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

15
Эй, приятель, не могли бы вы сказать мне, откуда эта магия 100? Почему не 101 или 99? Спасибо
Кароли

@Karoly я думаю, что это может быть и 1. Не важно. Только это должно быть меньше реальной длины клавиатуры
Влад

@Karoly в основном, он сравнивает размер окна с размером корневого представления вашей деятельности. Внешний вид программной клавиатуры не влияет на размер главного окна. так что вы все еще можете понизить значение 100.
mr5

Магическое число зависит от вашего расположения верхней панели среди других вещей. Так что это относительно вашего приложения. Я использовал 400 в одном из моих.
Мортен Холмгаард

помните, что onGlobalLayout вызывается каждый кадр, поэтому убедитесь, что вы не делаете там тяжелые вещи.
Акшай Гаонкар

8

Я использовал это в качестве основы: 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);

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


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

@depperm getActivity () относится к фрагментам, попробуйте вместо этого YourActivityName.this. См. Также: stackoverflow.com/questions/14480129/…
Кристофер Хакл,


6

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

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

adb shell dumpsys window InputMethod | grep "mHasSurface"

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


10
Это полезно только во время разработки, а не для использования в приложении. (У пользователей не будет запущен adb.)
ToolmakerSteve

5

Так что после долгого времени игры с 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

Удивительное использование отражений
kaustubhpatange

4

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

На основной деятельности:

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

4

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

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

3

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

Это будет называться ОЧЕНЬ часто
Денис Княжев

В каких случаях это будет отличаться от ответа @BrownsooHan? Я ищу способ, которым показывает приложение, которое рисует поверх других приложений, чтобы убраться с клавиатуры.
Эван Ланглуа

Его ответ в основном такой же, как и у меня, только я ответил за много месяцев до него, и у него больше голосов.
PearsonArtPhoto

3

Попробуйте этот код, он действительно работает, если 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;
}

IsKeyboardShown продолжает вызывать себя, когда он не показан.
Мандип Сингх,

2

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

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

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

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


1

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

1
Можете ли вы улучшить этот ответ на более конкретном примере со всем импортом и рабочим примером?
User3

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

1

Ответ @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
}

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


1

Наконец-то появился прямой путь от Android R на базе Kotlin.

 val imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
     //Ime is visible
     //Lets move our view by the height of the IME
     view.translationX = imeInsets.bottom }

0

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

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


Не работает для меня Я получаю только ключ Enter в OnEditorAction.
3c71

0

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

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

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

как это назвать и где?
Махди Астаней

0

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

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

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

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

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

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


0

Как вы, наверное, знаете, Клавиатура 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.


на самом деле не взломать, не работает в случае вложенного фрагмента. Не могу сказать о деятельности, так как я еще не пробовал это на этом.
Антроид

0

Я преобразовал ответ в 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

            }
        }
    }
}

0

Он работает с настройкой AdjustNothing, и используются события жизненного цикла. Также с Kotlin:

/**
 * This class uses a PopupWindow to calculate the window height when the floating keyboard is opened and closed
 *
 * @param activity The parent activity
 *  The root activity that uses this KeyboardManager
 */
class KeyboardManager(private val activity: AppCompatActivity) : PopupWindow(activity), LifecycleObserver {

    private var observerList = mutableListOf<((keyboardTop: Int) -> Unit)>()

    /** The last value of keyboardTop */
    private var keyboardTop: Int = 0

    /** The view that is used to calculate the keyboard top  */
    private val popupView: View?

    /** The parent view  */
    private var parentView: View

    var isKeyboardShown = false
        private set

    /**
     * Create transparent view which will be stretched over to the full screen
     */
    private fun createFullScreenView(): View {
        val view = LinearLayout(activity)
        view.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT)
        view.background = ColorDrawable(Color.TRANSPARENT)
        return view
    }

    init {
        this.popupView = createFullScreenView()
        contentView = popupView

        softInputMode = LayoutParams.SOFT_INPUT_ADJUST_RESIZE or LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
        inputMethodMode = INPUT_METHOD_NEEDED

        parentView = activity.findViewById(android.R.id.content)

        width = 0
        height = LayoutParams.MATCH_PARENT

        popupView.viewTreeObserver.addOnGlobalLayoutListener {
            val rect = Rect()
            popupView.getWindowVisibleDisplayFrame(rect)

            val keyboardTop = rect.bottom
            if (this.keyboardTop != keyboardTop) {
                isKeyboardShown = keyboardTop < this.keyboardTop
                this.keyboardTop = keyboardTop
                observerList.forEach { it(keyboardTop) }
            }
        }
        activity.lifecycle.addObserver(this)
    }

    /**
     * This must be called after the onResume of the Activity or inside view.post { } .
     * PopupWindows are not allowed to be registered before the onResume has finished
     * of the Activity
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun start() {
        parentView.post {
            if (!isShowing && parentView.windowToken != null) {
                setBackgroundDrawable(ColorDrawable(0))
                showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0)
            }
        }
    }

    /**
     * This manager will not be used anymore
     */
    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun close() {
        activity.lifecycle.removeObserver(this)
        observerList.clear()
        dismiss()
    }

    /**
     * Set the keyboard top observer. The observer will be notified when the keyboard top has changed.
     * For example when the keyboard is opened or closed
     *
     * @param observer The observer to be added to this provider
     */
    fun registerKeyboardTopObserver(observer: (keyboardTop: Int) -> Unit) {
        observerList.add(observer)
    }
}

Полезный способ держать вид всегда над клавиатурой

fun KeyboardManager.updateBottomMarginIfKeyboardShown(
        view: View,
        activity: AppCompatActivity,
        // marginBottom of view when keyboard is hide
        marginBottomHideKeyboard: Int,
        // marginBottom of view when keybouard is shown
        marginBottomShowKeyboard: Int
) {
    registerKeyboardTopObserver { bottomKeyboard ->
        val bottomView = ViewUtils.getFullViewBounds(view).bottom
        val maxHeight = ScreenUtils.getFullScreenSize(activity.windowManager).y
        // Check that view is within the window size
        if (bottomView < maxHeight) {
            if (bottomKeyboard < bottomView) {
                ViewUtils.updateMargin(view, bottomMargin = bottomView - bottomKeyboard +
                        view.marginBottom + marginBottomShowKeyboard)
            } else ViewUtils.updateMargin(view, bottomMargin = marginBottomHideKeyboard)
        }
    }
}

Где getFullViewBounds

fun getLocationOnScreen(view: View): Point {
    val location = IntArray(2)
    view.getLocationOnScreen(location)
    return Point(location[0], location[1])
}

fun getFullViewBounds(view: View): Rect {
     val location = getLocationOnScreen(view)
     return Rect(location.x, location.y, location.x + view.width,
            location.y + view.height)
 }

Где getFullScreenSize

fun getFullScreenSize(wm: WindowManager? = null) =
            getScreenSize(wm) { getRealSize(it) }

private fun getScreenSize(wm: WindowManager? = null, block: Display.(Point) -> Unit): Point {
    val windowManager = wm ?: App.INSTANCE.getSystemService(Context.WINDOW_SERVICE)
            as WindowManager
    val point = Point()
    windowManager.defaultDisplay.block(point)
    return point
}

Где updateMargin

fun updateMargin(
        view: View,
        leftMargin: Int? = null,
        topMargin: Int? = null,
        rightMargin: Int? = null,
        bottomMargin: Int? = null
) {
    val layoutParams = view.layoutParams as ViewGroup.MarginLayoutParams
    if (leftMargin != null) layoutParams.leftMargin = leftMargin
    if (topMargin != null) layoutParams.topMargin = topMargin
    if (rightMargin != null) layoutParams.rightMargin = rightMargin
    if (bottomMargin != null) layoutParams.bottomMargin = bottomMargin
    view.layoutParams = layoutParams
}

-1

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

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

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

Вопрос был связан с тем, чтобы узнать, показывает ли клавиатура или нет
Гопал Сингх Сирви

-1

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

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

}

Это будет работать только на аппаратной клавиатуре, а не на программной
anthonymonori 13.10.16

-1

Я написал образец .

Этот репозиторий может помочь определить состояние клавиатуры, не предполагая, что «клавиатура должна быть больше, чем X часть экрана»


-1

Если вы поддерживаете apis для AndroidR в своем приложении, вы можете использовать метод ниже.

In kotlin :
    var imeInsets = view.rootWindowInsets.getInsets(Type.ime()) 
    if (imeInsets.isVisible) { 
        view.translationX = imeInsets.bottom 
    }

Примечание: это доступно только для AndroidR, и ниже версия Android должна следовать некоторым другим ответам, или я обновлю это для этого.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.