ソフトウェア(別名「ソフト」)キーボードが画面に表示されているかどうかをAndroidで検出する方法はありますか?
34 に答える
これは私にとってはうまくいきます。おそらく、これはすべてのバージョンで常に最良の方法です。
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)
}
}
}
});
これを試して:
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
この場合、私のルートビューを指しているビューにすぎません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) { // Value should be less than keyboard's height
Log.e("MyActivity", "keyboard opened");
} else {
Log.e("MyActivity", "keyboard closed");
}
}
});
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
これを基礎として使用しました:https://rogerkeays.com/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);
もちろん、理想的なソリューションではありませんが、仕事は完了します。
showSoftInput() および hideSoftInput() のコールバック結果を使用して、キーボードのステータスを確認できます。詳細とサンプル コードは次の URL にあります。
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
これは、私が必要とする要件に対してはるかに複雑ではありませんでした。これが役立つことを願っています:
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();
}
この回答を参照できます- https://stackoverflow.com/a/24105062/3629912
それはいつも私のために働いた。
adb shell dumpsys window InputMethod | grep "mHasSurface"
ソフトウェア キーボードが表示されている場合は true を返します。
次のように、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 が Shown の場合、この関数は真の値を返します....
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;
}
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();
}
}
}
ソフトキーボードが表示されているかどうかを確認するための回避策を次に示します。
- ActivityManager.getRunningServices(max_count_of_services); を使用して、システムで実行中のサービスを確認します。
- 返された ActivityManager.RunningServiceInfo インスタンスから、ソフト キーボード サービスのclientCount値を確認します。
- 前述の clientCount は、ソフト キーボードが表示されるたびにインクリメントされます。たとえば、clientCount が最初は 1 だった場合、キーボードが表示されると 2 になります。
- キーボードを閉じると、clientCount が減少します。この場合、1 にリセットされます。
一部の一般的なキーボードには、classNames に特定のキーワードが含まれています。
- Google AOSP = IME
- スワイプ = IME
- Swiftkey = KeyboardService
- Fleksy = キーボード
- Adaptxt = IME (KPTAdaptxtIME)
- スマート = キーボード (SmartKeyboard)
ActivityManager.RunningServiceInfo から、ClassNames で上記のパターンを確認します。また、ActivityManager.RunningServiceInfo のclientPackage =android は、キーボードがシステムにバインドされていることを示します。
上記の情報を組み合わせて、ソフト キーボードが表示されているかどうかを厳密に確認できます。
同様の問題がありました。画面上の Enter ボタンに反応する必要がありました (これにより、キーボードが非表示になりました)。この場合、キーボードを開いたときに使用したテキスト ビューの OnEditorAction をサブスクライブできます。編集可能なボックスが複数ある場合は、それらすべてをサブスクライブします。
アクティビティでは、キーボードを完全に制御できるため、すべての開始イベントと終了イベントをリッスンすれば、キーボードが開いているかどうかに関係なく問題に直面することはありません。
答えを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
}
}
}
}
アプリで AndroidR の API をサポートしている場合は、以下の方法を使用できます。
In kotlin :
var imeInsets = view.rootWindowInsets.getInsets(Type.ime())
if (imeInsets.isVisible) {
view.translationX = imeInsets.bottom
}
注:これはAndroidRでのみ利用可能で、Androidバージョン以下では他の回答に従う必要があります。そうしないと、そのために更新されます。
を使用している可能性があります:
@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) {
}
私はこれを次のように行いましたが、あなたの目標がキーボードを閉じたり開いたりすることである場合にのみ関連します。
閉じる例: (キーボードが既に閉じているかどうかを確認し、そうでない場合は閉じる)
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);
}
});