web-dev-qa-db-ja.com

ソフトウェアキーボードがAndroidデバイスで表示されているかどうかを検出する方法

ソフトウェア(別名「ソフト」)キーボードが画面に表示されているかどうかを検出する方法はAndroidにありますか?

201
andreea

直接的な方法はありません。 http://groups.google.com/group/Android-platform/browse_thread/thread/1728f26f2334c060/5e4910f0d9eb898a を参照してください。AndroidチームのDianne Hackbornが返信しました。ただし、#onMeasureでウィンドウサイズが変更されたかどうかを確認することで間接的に検出できます。 Androidでソフトウェアキーボードの表示を確認するにはどうすればいいですか? を参照してください。

61
user770428

これは私のために働きます。たぶん、これは常に最善の方法ですすべてのバージョンに対して

OnGlobalLayoutメソッドは何度も呼び出すので、キーボードの可視性のプロパティを作成し、この変更を遅延させて観察することは効果的です。また、デバイスの回転をチェックして、windowSoftInputModeadjustNothingではないことを確認してください。

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)
            }
        }
    }
});
236
Brownsoo Han

これを試して:

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

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

私はこれに使用できる簡単なクラスを作成しました。 https://github.com/ravindu1024/Android-keyboardlistener 。プロジェクトにコピーして次のように使用するだけです。

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

非常に簡単

1.ルートビューにidを付けます

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

私は基礎としてこれを使用しました: http://www.ninthavenue.jp.h/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);

確かに理想的な解決策ではありませんが、それは仕事を成し遂げます。

6

ShowSoftInput()およびhideSoftInput()のコールバック結果を使用してキーボードのステータスを確認できます。完全な詳細とコード例

http://www.ninthavenue.jp.h/how-to-check-if-the-software-keyboard-is-shown-in-Android

6
Roger Keays

あなたはこの答えを参照することができます - https://stackoverflow.com/a/24105062/3629912

それはいつも私のために働きました。

adb Shell dumpsys window InputMethod | grep "mHasSurface"

ソフトウェアキーボードが表示されている場合はtrueを返します。

4
l'-'l

これは私が必要としていた要件にとってはそれほど複雑ではありませんでした。これが助けになることを願っています:

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

そのため、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
2
TheWanderer

キーボードの状態を確認する必要がある場合、これはうまくいくはずです。

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()はdpToPxを変換する関数です。

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

私の場合、私は自分のレイアウトで管理するためのEditTextを一つしか持っていなかったので、私は聖霊降臨祭を思いつきました this 解決策。これはうまく機能します。基本的にはフォーカスをリッスンし、フォーカスが変更された場合、または戻る/終了ボタンが押された場合にローカルブロードキャストを送信するカスタムのEditTextです。 clearFocus()を呼び出すと最初のフォーカス可能ビューにフォーカスが再割り当てされるため、Android:focusable="true"Android:focusableInTouchMode="true"を使用してレイアウトにダミーのViewを配置する必要があります。ダミービューの例

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

追加情報

レイアウト変更の違いを検出するソリューションは、画面密度に強く依存するため、あまりうまくいきません。100pxは、特定のデバイスでは非常に大きくなり、他のデバイスでは何も誤検出されないからです。ベンダによってもキーボードが異なります。

2
TheRedFox

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;
}
2
Ravi Makvana

次のように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
                }
            }
        });
2
PearsonArtPhoto
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
user3068659

@ 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
V. Kalyuzhnyu

私はその答えを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
Emre Akcan

私は同様の問題を抱えていました。私は(キーボードを隠した)画面上のEnterボタンに反応する必要がありました。この場合、あなたはキーボードが開かれたテキストビューのOnEditorActionを購読することができます - あなたが複数の編集可能なボックスを持っているなら、それからそれらすべてを購読してください。

アクティビティではキーボードを完全に制御できます。すべての開閉イベントを聴いても、キーボードが開いていても開いていなくても、問題に直面することは決してありません。

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

ご存知かもしれませんが、Androidソフトウェアのキーボードは、タイプ入力の可能性がある場合にのみ表示されます。言い換えれば、キーボードは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
sharath bhargav

ソフトキーボードが表示されているかどうかを知るための回避策は次のとおりです。

  1. ActivityManager.getRunningServices(max_count_of_services)を使用して、システム上で実行中のサービスを確認します。
  2. 返されたActivityManager.RunningServiceInfoインスタンスから、clientCountソフトキーボードサービスの値を確認します。
  3. 前述のclientCountは毎回インクリメントされ、ソフトキーボードが表示されます。たとえば、clientCountが最初は1だった場合、キーボードが表示されているときは2になります。
  4. キーボードを閉じると、clientCountは減少します。この場合、1にリセットされます。

一般的なキーボードの中には、classNameに特定のキーワードを持つものがあります。

  1. Google AOSP = IME
  2. Swype = IME
  3. Swiftkey = KeyboardService
  4. Fleksy =キーボード
  5. Adaptxt = IME(KPTAdaptxtIME)
  6. スマート=キーボード(SmartKeyboard)

ActivityManager.RunningServiceInfoから、ClassNamesの上記のパターンを確認します。 ActivityManager.RunningServiceInfoのclientPackage= Androidは、キーボードがシステムにバインドされていることを示します。

上記の情報は、ソフトキーボードが表示されているかどうかを調べる厳密な方法のために組み合わせることができます。

0
Satishkumar

これを見つける直接的な方法があります。そして、それはレイアウトの変更を必要としません。
つまり、没入型フルスクリーンモードでも機能します。
しかし、残念ながら、すべてのデバイスで機能するわけではありません。だからあなたはあなたのデバイスでそれをテストする必要があります。

トリックは、あなたがソフトキーボードを隠したり表示したりしようとし、その試みの結果を捉えることです。
それが正しく機能すれば、キーボードは実際には表示されず隠されません。私達はちょうど国家を求めます。

最新の状態に保つには、単にこの操作を繰り返します。 Handlerを使用して、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
fies