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

Мне нужно сделать очень простую вещь-выяснить, отображается ли программная клавиатура. Это возможно в Android?

30 ответов


ОТВЕТ добавлено 25 января 2012

С момента написания приведенного ниже ответа, кто-то сообщил мне о существовании ViewTreeObserver и друзья, API, которые скрывались в SDK с версии 1.

вместо того, чтобы требовать пользовательского типа макета, гораздо более простым решением является предоставление корневого представления вашей активности известного идентификатора, скажем @+id/activityRoot, подключите GlobalLayoutListener к ViewTreeObserver и оттуда вычислите разница в размере между корнем вида вашей деятельности и размером окна:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
        if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard...
            // ... do something here
        }
     }
});

использование утилиты, такой как:

public static float dpToPx(Context context, float valueInDp) {
    DisplayMetrics metrics = context.getResources().getDisplayMetrics();
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}

легко!

Примечание: Ваше приложение должно установить этот флаг в Манифесте Android android:windowSoftInputMode="adjustResize" в противном случае решение не будет работать.

ОРИГИНАЛЬНЫЙ ОТВЕТ

Да, это возможно, но это намного сложнее, чем это должно быть.

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

import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.LinearLayout;

/*
 * LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when 
 * the soft keyboard is shown and hidden (something Android can't tell you, weirdly). 
 */

public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {

    public LinearLayoutThatDetectsSoftKeyboard(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public interface Listener {
        public void onSoftKeyboardShown(boolean isShowing);
    }
    private Listener listener;
    public void setListener(Listener listener) {
        this.listener = listener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int height = MeasureSpec.getSize(heightMeasureSpec);
        Activity activity = (Activity)getContext();
        Rect rect = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int statusBarHeight = rect.top;
        int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
        int diff = (screenHeight - statusBarHeight) - height;
        if (listener != null) {
            listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);       
    }

    }

затем в вашем классе активности...

public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);
        mainLayout.setListener(this);
        ...
    }


    @Override
    public void onSoftKeyboardShown(boolean isShowing) {
        // do whatever you need to do here
    }

    ...
}

надеюсь, это кому-то поможет.

новый ответ, который дал Рубен Скреттон, велик и действительно эффективен, но он действительно работает, только если вы установите windowSoftInputMode в adjustResize. Если вы установите его в adjustPan, по-прежнему невозможно определить, видна ли клавиатура с помощью его фрагмента кода. Чтобы обойти это, я сделал эту крошечную модификацию кода выше.

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    activityRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
    if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
        ... do something here
    }
 }
}); 

извините за поздний ответ, но я создал небольшой вспомогательный класс для обработки открытых / закрытых событий с уведомлением слушателей и других полезных вещей, может быть, кто-то найдет его полезным:

import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;

import java.util.LinkedList;
import java.util.List;

public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {

    public interface SoftKeyboardStateListener {
        void onSoftKeyboardOpened(int keyboardHeightInPx);
        void onSoftKeyboardClosed();
    }

    private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
    private final View activityRootView;
    private int        lastSoftKeyboardHeightInPx;
    private boolean    isSoftKeyboardOpened;

    public SoftKeyboardStateWatcher(View activityRootView) {
        this(activityRootView, false);
    }

    public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
        this.activityRootView     = activityRootView;
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout() {
        final Rect r = new Rect();
        //r will be populated with the coordinates of your view that area still visible.
        activityRootView.getWindowVisibleDisplayFrame(r);

        final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
            isSoftKeyboardOpened = true;
            notifyOnSoftKeyboardOpened(heightDiff);
        } else if (isSoftKeyboardOpened && heightDiff < 100) {
            isSoftKeyboardOpened = false;
            notifyOnSoftKeyboardClosed();
        }
    }

    public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
        this.isSoftKeyboardOpened = isSoftKeyboardOpened;
    }

    public boolean isSoftKeyboardOpened() {
        return isSoftKeyboardOpened;
    }

    /**
     * Default value is zero {@code 0}.
     *
     * @return last saved keyboard height in px
     */
    public int getLastSoftKeyboardHeightInPx() {
        return lastSoftKeyboardHeightInPx;
    }

    public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.add(listener);
    }

    public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
        listeners.remove(listener);
    }

    private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
        this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;

        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardOpened(keyboardHeightInPx);
            }
        }
    }

    private void notifyOnSoftKeyboardClosed() {
        for (SoftKeyboardStateListener listener : listeners) {
            if (listener != null) {
                listener.onSoftKeyboardClosed();
            }
        }
    }
}

пример использования:

final SoftKeyboardStateWatcher softKeyboardStateWatcher 
    = new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);

// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks

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

поэтому я взял вышеуказанные ответы и объединил и немного доработал их...

public interface OnKeyboardVisibilityListener {


    void onVisibilityChanged(boolean visible);
}

public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
    final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);

    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        private boolean wasOpened;

        private final int DefaultKeyboardDP = 100;

        // From @nathanielwolf answer...  Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
        private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);

        private final Rect r = new Rect();

        @Override
        public void onGlobalLayout() {
            // Convert the dp to pixels.
            int estimatedKeyboardHeight = (int) TypedValue
                    .applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());

            // Conclude whether the keyboard is shown or not.
            activityRootView.getWindowVisibleDisplayFrame(r);
            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            boolean isShown = heightDiff >= estimatedKeyboardHeight;

            if (isShown == wasOpened) {
                Log.d("Keyboard state", "Ignoring global layout change...");
                return;
            }

            wasOpened = isShown;
            listener.onVisibilityChanged(isShown);
        }
    });
}

работает для меня :)

Примечание: Если вы заметили, что DefaultKeyboardDP не подходит для вашего устройства играть со значением и оставить комментарий для всех, чтобы знать, что должно быть значение... в итоге мы получим правильное значение, чтобы соответствовать всем устройства!


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

  1. порог разности высот должен быть определен как 128 dp, а не 128 пикселей.
    См.Google design doc о метриках и сетке, 48 dp удобный размер для объекта касания и 32 dp является минимальным для кнопок. Общая мягкая клавиатура должна включать 4 ряда клавиш, поэтому минимальная высота клавиатуры должна быть: 32 dp * 4 = 128 dp, это означает, что пороговый размер должен передаваться в пиксели путем умножения плотности устройства. Для устройств xxxhdpi (плотность 4) порог высоты мягкой клавиатуры должен составлять 128 * 4 = 512 пикселей.

  2. разница в высоте между корневым видом и его видимой областью:
    высота корня вид - статус бар высота - видимый каркас высота = корень вид снизу - видны внизу кадра, так как статус бар высота равна верхняя часть видимой рамки корневого вида.

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

я использовал немного времени, чтобы выяснить это... Я запустил некоторые CastExceptions, но понял, что вы можете заменить LinearLayout в макете.xml с именем класса.

такой:

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
    xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">

<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
    android:layout_width="fill_parent" android:layout_height="fill_parent"
    android:id="@+id/rlMaster" >
    <LinearLayout android:layout_width="fill_parent"
        android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>

          ....

</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>    


</LinearLayout>

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

... и если вы не хотите делать это на каждой странице, Я рекомендую вам использовать "MasterPage в Android". См. ссылку здесь: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx


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

public boolean hideSoftInput() {
    InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
    return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}

этот метод возвращает true, если клавиатура была показана перед скрытием.


проверка высоты элементов не является надежной, потому что некоторые клавиатуры, такие как WifiKeyboard имеют нулевую высоту.

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

https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android


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

final View root= findViewById(R.id.myrootview); 
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
    public void onGlobalLayout() {
        int heightDiff = root.getRootView().getHeight() - root.getHeight();

        Rect rectgle= new Rect();
        Window window= getWindow();
        window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
        int contentViewTop=                     
          window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
        if(heightDiff <= contentViewTop){
            //Soft KeyBoard Hidden
        }else{
            //Soft KeyBoard Shown
        }
     }
});

Я обнаружил, что комбинация метода @Reuben_Scratton вместе с методом @Yogesh работает лучше всего. Объединение их методов дало бы что-то вроде этого:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
       // ... do something here
    }
  }
});

вы можете наблюдать скрытие softkeyboard с помощью decorView activity.

public final class SoftKeyboardUtil {
    public static final String TAG = "SoftKeyboardUtil";
    public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
        final View decorView = activity.getWindow().getDecorView();
        decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect rect = new Rect();
                decorView.getWindowVisibleDisplayFrame(rect);
                int displayHight = rect.bottom - rect.top;
                int hight = decorView.getHeight();
                boolean hide = (double)displayHight / hight > 0.8 ;
                if(Log.isLoggable(TAG, Log.DEBUG)){
                    Log.d(TAG ,"DecorView display hight = "+displayHight);
                    Log.d(TAG ,"DecorView hight = "+ hight);
                    Log.d(TAG, "softkeyboard visible = " + !hide);
                }

                listener.onSoftKeyBoardVisible(!hide);

            }
        });
    }



    public interface OnSoftKeyBoardHideListener{
        void onSoftKeyBoardVisible(boolean visible);
    }
}

существует также решение с системными вставками, но оно работает только с API >= 21 (Android L). Скажите, что у вас есть BottomNavigationView, который является ребенком LinearLayout и вам нужно скрыть его, когда клавиатура отображается:

> LinearLayout
  > ContentView
  > BottomNavigationView

все, что вам нужно сделать, это продлить LinearLayout таким образом:

public class KeyboardAwareLinearLayout extends LinearLayout {
    public KeyboardAwareLinearLayout(Context context) {
        super(context);
    }

    public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public KeyboardAwareLinearLayout(Context context,
                                     @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
                                     int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
        int childCount = getChildCount();
        for (int index = 0; index < childCount; index++) {
            View view = getChildAt(index);
            if (view instanceof BottomNavigationView) {
                int bottom = insets.getSystemWindowInsetBottom();
                if (bottom >= ViewUtils.dpToPx(200)) {
                    // keyboard is shown
                    view.setVisibility(GONE);
                } else {
                    // keyboard is hidden
                    view.setVisibility(VISIBLE);
                }
            }
        }
        return insets;
    }
}

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


ни одно из этих решений будет работать для Lollipop как. В Леденец activityRootView.getRootView().getHeight() включает высоту панели кнопок, а измерение вида - нет. Я адаптировал лучшее/простое решение выше для работы с Lollipop.

    final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    Rect r = new Rect();
    //r will be populated with the coordinates of your view that area still visible.
    activityRootView.getWindowVisibleDisplayFrame(r);

    int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
    Resources res = getResources();
    // The status bar is 25dp, use 50dp for assurance
    float maxDiff =
        TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());

    //Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      float buttonBarHeight =
          TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
      maxDiff += buttonBarHeight;
    }
    if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
      ...do something here
    }
  }
});

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

final View activityRootView = findViewById(android.R.id.content);
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
                }
            }
        });

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

public interface OnKeyboardVisibilityListener {
    void onVisibilityChanged(boolean visible);
}

public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
    final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

        private boolean wasOpened;

    private final Rect r = new Rect();

        @Override
        public void onGlobalLayout() {
            activityRootView.getWindowVisibleDisplayFrame(r);

            int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
            boolean isOpen = heightDiff > 100;
            if (isOpen == wasOpened) {
                logDebug("Ignoring global layout change...");
                return;
            }

            wasOpened = isOpen;
            listener.onVisibilityChanged(isOpen);
        }
    });
}

это работает для меня.


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

import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;

/**
 * Detects Keyboard Status changes and fires events only once for each change
 */
public class KeyboardStatusDetector {
    KeyboardVisibilityListener visibilityListener;

    boolean keyboardVisible = false;

    public void registerFragment(Fragment f) {
        registerView(f.getView());
    }

    public void registerActivity(Activity a) {
        registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
    }

    public KeyboardStatusDetector registerView(final View v) {
        v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                v.getWindowVisibleDisplayFrame(r);

                int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
                    /** Check this variable to debounce layout events */
                    if(!keyboardVisible) {
                        keyboardVisible = true;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
                    }
                } else {
                    if(keyboardVisible) {
                        keyboardVisible = false;
                        if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
                    }
                }
            }
        });

        return this;
    }

    public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
        visibilityListener = listener;
        return this;
    }

    public static interface KeyboardVisibilityListener {
        public void onVisibilityChanged(boolean keyboardVisible);
    }
}

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

    new KeyboardStatusDetector()
            .registerFragment(fragment)  //register to a fragment 
            .registerActivity(activity)  //or register to an activity
            .registerView(view)          //or register to a view
            .setVisibilityListener(new KeyboardVisibilityListener() {
                @Override
                public void onVisibilityChanged(boolean keyboardVisible) {
                    if(keyboardVisible) {
                       //Do stuff for keyboard visible
                    }else {
                       //Do stuff for keyboard hidden
                    }
                }
            });

Примечание: используйте только один из вызовов" register". Все они работают одинаково и существуют только для удобства


вы можете попробовать это, отлично работает для меня:

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

if (imm.isAcceptingText()) {
    //Software Keyboard was shown..
} else {
    //Software Keyboard was not shown..
}

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

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

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

лучший подход, который я нашел после некоторого тестирования на различных экранах а приборы должны были использовать проценты. Получите разницу между содержимым decorView и ur app, а затем проверьте, каков процент этой разницы. Из статистики, которую я получил, большинство навигационных баров (независимо от размера, разрешения и т. д..) займет от 3% до 5% экрана. Где, как будто клавиатура открыта, она занимает от 47% до 55% экрана.

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


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

чтобы сохранить состояние клавиатуры в этом случае, сначала вы должны добавить android:windowSoftInputMode = "stateUnchanged" на AndroidManifest.xml. Однако вы можете заметить, что это на самом деле не решает всей проблемы-клавиатура не открывалась для меня, если она была открыта до изменения ориентации. В общем в других случаях поведение казалось правильным.

Затем нам нужно реализовать одно из решений, упомянутых здесь. Самый чистый, который я нашел, был Джорджа Майсурадзе-используйте булевый обратный вызов из hideSoftInputFromWindow:

InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);

Я сохранил это значение в моем фрагменте onSaveInstanceState метод и восстановил его onCreate. Затем я насильно показал клавиатуру в onCreateView если бы он имел значение true (он возвращает true, если клавиатура видна, прежде чем фактически скрывать ее до разрушение фрагмента).


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

final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.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.
        activityRootView.getWindowVisibleDisplayFrame(r);

        int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
        if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
             // ... do something here ... \
        }
    }
});

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

import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager

class SoftKeyboardStateWatcher(private val ctx: Context) {
  companion object {
    private const val DELAY = 10L
  }

  private val handler = Handler()
  private var isSoftKeyboardOpened: Boolean = false

  private val height: Int
    get() {
      val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
      val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
      method.isAccessible = true
      return method.invoke(imm) as Int
    }

  private val task: Runnable by lazy {
    Runnable {
      start()
      if (!isSoftKeyboardOpened && height > 0) {
        isSoftKeyboardOpened = true
        notifyOnSoftKeyboardOpened(height)
      } else if (isSoftKeyboardOpened && height == 0) {
        isSoftKeyboardOpened = false
        notifyOnSoftKeyboardClosed()
      }
    }
  }

  var listener: SoftKeyboardStateListener? = null

  interface SoftKeyboardStateListener {
    fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
    fun onSoftKeyboardClosed()
  }

  fun start() {
    handler.postDelayed(task, DELAY)
  }

  fun stop() {
    handler.postDelayed({
      if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
    }, DELAY * 10)
  }

  private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
    listener?.onSoftKeyboardOpened(keyboardHeightInPx)
  }

  private fun notifyOnSoftKeyboardClosed() {
    listener?.onSoftKeyboardClosed()
  }
}

вот мое решение, и оно работает. Вместо того, чтобы искать размер пикселя, просто проверьте, что высота представления содержимого изменилась или нет:

// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        private int oldHeight;

        @Override
        public void onGlobalLayout() {
            int newHeight = commentsContent.getMeasuredHeight();
            if (newHeight < oldHeight) {
                // Check for the keyboard showing in case the height difference
                // is a result of orientation change
                if (isSoftKeyboardShowing(CommentsActivity.this)) {
                    // Keyboard is showing so scroll to the latest comment
                    scrollToLatestComment();
                }
            }
            oldHeight = newHeight;
        }

    });


public static boolean isSoftKeyboardShowing(Activity activity) {
    InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
    return inputMethodManager.isActive();
}

нет никакой жесткий код. Лучший способ-изменить размер ваших представлений, а также сосредоточиться на EditText с помощью KeyBord Show. Вы можете сделать это, добавив свойство resize on activity в файл манифеста, используя приведенный ниже код.

android:windowSoftInputMode="adjustResize"


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

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

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

Вы найти реализацию здесь:https://stackoverflow.com/a/27567074/2525452


Я думаю, что этот метод поможет вам узнать, является ли keybord видимым или нет.

 public Boolean isSoftKeyBoardVisible(){
    InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);

    if (imm.isAcceptingText()) {
        Log.d(TAG,"Software Keyboard was shown");
        return true;
    } else {
        Log.d(TAG,"Software Keyboard was not shown");
        return false;
    }

}

новый ответ Рубена Скрэттона (вычислить HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();) не будет работать в действии, если вы установите полупрозрачный режим строки состояния.

если вы используете прозрачный статус бар , activityRootView.getHeight() никогда не изменится погода мягкая клавиатура видна. он всегда будет возвращать высоту активности и строку состояния.

например, Nexus 4, Android 5.0.1, set android:windowTranslucentStatus к истине, он вернется 1184 навсегда, даже ime имеют opend. Если вы установите android:windowTranslucentStatus false, то он будет верните высоту правильно, если ime невидимый, он возвращает 1134 (не включает строку состояния)。закройте ime, он вернет 5xx возможно (зависит от высоты ime)

Я не знаю, погода это ошибка, Я пробовал на 4.4.4 и 5.0.1, результат тот же.

Итак, до сих пор, второй наиболее согласованный ответ, решение Качи будет самым безопасным способом расчета высоты ime. Вот копия:

final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new        OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);

int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
    ... do something here
    }
 }
}); 

метод не нужен LayoutListener

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

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


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

public static boolean isKeyboardShown(Context context, View view) {
        if (context == null || view == null) {
            return false;
        }
        InputMethodManager imm = (InputMethodManager) context
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        return imm.hideSoftInputFromWindow(view.getWindowToken(), 0); 
}

imm.hideSoftInputFromWindow возвращает логическое значение.

спасибо,


if (keyopen())
{
                InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);            
}

вышеуказанная функция-это то, что я использую, чтобы проверить, видна ли клавиатура. Если да, то я его закрываю.

ниже показаны два необходимых метода.

во-первых, определите работоспособную высоту окна в onCreate.

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

//  add to onCreate method
    Rect rectgle= new Rect();
    Window window= getWindow();
    window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
    sheight= rectgle.bottom;
//

} 

затем добавьте логический метод, который получает высоту окна в этом экземпляре. Если он не соответствует оригиналу (при условии, что вы не меняете его по пути...) тогда клавиатура открыть.

public boolean keyopen()
{
    Rect rectgle= new Rect();
    Window window= getWindow();
    window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
    int curheight= rectgle.bottom;

    if (curheight!=sheight)
    {
        return true;
    }
    else
    {
        return false;
    }
}

frotz выступает!


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

public int getStatusBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

public int getNavigationBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

public boolean isKeyboardHidden() {
    int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
            - getSupportActionBar().getHeight();
    return delta <= 0;
}

это работает для планшетов. Когда navigationbar отображается горизонтально.