私は非常に簡単なことをする必要があります-ソフトウェアキーボードが表示されているかどうかを確認します。これはAndroidで可能ですか?
私は非常に簡単なことをする必要があります-ソフトウェアキーボードが表示されているかどうかを確認します。これはAndroidで可能ですか?
回答:
新しい回答が 2012年1月25日に追加されました
以下の回答を書いてから、誰かが私にバージョン1以降のSDKに潜んでいるAPIであるViewTreeObserverとその友人の存在を教えてくれました。
カスタムレイアウトタイプを必要とするよりもはるかに簡単な解決策は、アクティビティのルートビューに既知のIDを与え、たとえば@+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
}
...
}
((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)
android.R.id.content
)を使用してこれを試すとSystem
、アプリケーションではなく、アプリケーションが高さを変更するエンティティであると自信を持って言うことができます。Androidチームが休憩を取り、少なくともSoftKeyboard入力に関する基本的なことを教えてくれれば、はるかに安全になります。
heightDiff
常にアクションバーの高さが含まれることに注意してください。その高さが定数よりも大きいかどうかをテストすることで無視された新しい答えでは、Nexus 4などのxxhdpiデバイスでは100ピクセルでは不十分です。このハッキーな作業を本当に使用したい場合は、その値をDPに変換することを検討してください。周り。
うまくいけば、これは誰かを助けるのに役立ちます。
Reuben Scrattonが与えた新しい答えは素晴らしく、本当に効率的ですが、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 > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
... do something here
}
}
});
TwoDScrollerView
類似したカスタムからキーボードの状態を検出しようとしました。子はシンプルではなくカスタムレイアウト(拡張)でしたが、設定にもかかわらず、推奨される解決策を使用してキーボードを検出できませんでした。ありがとう!ImageView
RelativeLayout
android:windowSoftInputMode="adjustResize"
ActionBar
してActionBarSherlock
。どうもありがとう!ちなみに、方法がありますr.height()
:)
heightDiff > root.getRootView().getHeight() / 4
高解像度デバイスでの作業に適した値です。100pxは短いです。1080x1920解像度のNexus 5の場合、1920-(996-75)>?100 = 999 1920-(1776-75)>?100 = 219 // 480x800解像度、800-(800-38)のGalaxy s2でキーボードが稼働している>?100 = 38800-(410-38)>?100 = 428 //キーボードが上がっているので、マジックナンバー100pxでは不十分です。
コンピュータに関しては永遠にありますが、この質問は信じられないほど関連性があります!
だから私は上記の答えを取り、それらを少し組み合わせて洗練させました...
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がお使いのデバイスに適合しない ことに気付いた場合は、値を使用してすべてのデバイスに適した正しい値を取得できるようにコメントを投稿してください。
詳細については、サイボーグの実装を確認してください
遅い答えで申し訳ありませんが、通知リスナーやその他の便利なものを使用して開閉イベントを処理するための小さなヘルパークラスを作成しました。
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
getLastKeyboardHeightInPx()
とその行の高さが含まれないため、これらは明らかにキーボード自体の一部ではありません。それを考慮に入れる方法を知っていますか?
高密度デバイスのソフトキーボードの可視性を誤って検出しないようにするためのいくつかの改善:
高さの差のしきい値は、128ピクセルではなく、128 dpとして定義する必要があります。
参照してくださいメトリクスとグリッドについて、Googleの設計ドキュメント、48 DPは、タッチオブジェクトのための快適なサイズであり、32 DPは、ボタンの最小です。汎用ソフトキーボードには4行のキーボタンが含まれている必要があるため、キーボードの最小の高さは 32 dp * 4 = 128 dpである必要があります。xxxhdpiデバイス(密度4)の場合、ソフトキーボードの高さのしきい値は128 * 4 = 512ピクセルにする必要があります。
ルートビューとその表示領域の
高さの差:ルートビューの高さ-ステータスバーの高さ-表示フレームの高さ=ルートビューの下部-表示フレームの下部。ステータスバーの高さはルートビューの表示フレームの上部に等しいため。
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;
}
少し時間をかけてこれを理解しました...いくつかのCastExceptionを実行しましたが、layout.xmlのLinearLayoutをクラスの名前に置き換えることができることがわかりました。
このような:
<?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 in Android」を使用することをお勧めします。ここのリンクを参照してください:http : //jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
WifiKeyboardなどの一部のキーボードの高さがゼロであるため、要素の高さを確認することは信頼できません。
代わりに、showSoftInput()およびhideSoftInput()のコールバック結果を使用して、キーボードのステータスを確認できます。詳細とサンプルコード
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
アイデアは、キーボードを非表示にすると同時にソフト入力の状態をチェックする必要がある場合は、次のソリューションを使用することです。
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
このメソッドは、キーボードが非表示になる前に表示された場合はtrueを返します。
@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
}
}
});
アクティビティのdecorViewを使用して、ソフトキーボードの非表示を確認できます。
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);
}
}
差分コーディングを想定する代わりに、アプリケーションにメニューオプションがあったため、このようなことをしました。
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
}
}
});
システムインセットの解決策もありますが、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
値で変更されるというものです。
このために役立つ隠しメソッドがあります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()
}
}
これらのソリューションはいずれも、Lollipopでそのままでは機能しません。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
}
}
});
固定数の追加を提案する上記のソリューションのほとんどを使用しているときに、バグに遭遇しました。
S4のdpiは高いため、ナビゲーションバーの高さが100pxになり、私のアプリはキーボードが常に開いていると考えています。
だから、すべての新しいハイレゾ電話がリリースされているので、ハードコードされた値を使用することは長期的には良い考えではないと思います。
さまざまな画面やデバイスでいくつかのテストを行った後に見つけたより良いアプローチは、パーセンテージを使用することでした。decorViewとurアプリのコンテンツの違いを取得し、その違いの割合を確認してください。私が得た統計から、ほとんどのナビゲーションバー(サイズ、解像度などに関係なく)は画面の3%から5%の間です。キーボードが開いているかのように、画面の47%から55%を占めていました。
結論として、私の解決策は、diffが10%を超えているかどうかを確認することでした。
私はReubanの回答のわずかな変形を使用しました。これは、特定の状況、特に高解像度デバイスでより役立つことが判明しました。
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
}
}
});
R.id.activityRoot
そのまま使用できandroid.R.id.content
ます。
コンピュータに関しては永遠にありましたが、この質問は信じられないほど関連性があります!だから私は上記の答えを取り、それらを少し組み合わせて洗練させました...
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);
}
});
}
わたしにはできる。
これを試して:
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 ... \\
}
}
});
私の答えは基本的にはカチの答えと同じですが、アプリ全体で使用される方法を整理するために、それを素晴らしいヘルパークラスにラップしました。
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
}
}
});
注:「登録」呼び出しの1つのみを使用してください。それらはすべて同じように機能し、便宜上そこにのみあります
あなたはこれを試すことができ、私にとって素晴らしい働きをします:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
ビューページャー内でフラグメントの方向を変更するときに、キーボードの状態を維持するのが困難でした。理由はわかりませんが、不安定で、標準のアクティビティとは異なる動作をするだけです。
この場合にキーボードの状態を維持するには、最初ににを追加android:windowSoftInputMode = "stateUnchanged"
する必要がありますAndroidManifest.xml
。ただし、これで問題全体が実際に解決されるわけではないことに気付かれるかもしれません-方向を変更する前にキーボードが開かれていた場合、キーボードが開かれませんでした。他のすべての場合では、動作は正しいように見えました。
次に、ここで説明したソリューションの1つを実装する必要があります。私が見つけた最もクリーンなものはGeorge Maisuradzeのものでした-hideSoftInputFromWindowからのブールコールバックを使用します。
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
この値をFragmentのonSaveInstanceState
メソッドに格納して取得しましたonCreate
。次に、onCreateView
値がの場合はキーボードを強制的にtrue
表示しました(フラグメントが破棄される前にキーボードを実際に非表示にする前にキーボードが表示されている場合は、trueを返します)。
これが私の解決策であり、うまくいきます。ピクセルサイズを探す代わりに、コンテンツビューの高さが変更されたかどうかを確認します。
// 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();
}
これを見つける直接的な方法があります。また、レイアウトを変更する必要はありません。
したがって、没入型フルスクリーンモードでも動作します。
秘訣は、ソフトキーボードを表示または非表示にして、その試行の結果をキャプチャしようとすることです。
パニックは発生しません。これは実際にはキーボードを表示または非表示にするものではありません。状態をお願いするだけです。
最新の状態に保つには、ハンドラを使用して、たとえば200ミリ秒ごとに操作を繰り返すだけです。
ここで実装を見つけます:https : //stackoverflow.com/a/27567074/2525452
この方法は、キーボードが表示されているかどうかを確認するのに役立つと思います。
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;
}
}
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
半透明のステータスバーモードを設定すると、Reuben Scrattonの新しい回答(HeightDiffを計算する )が動作しなくなります。
半透明のステータスバーを使用する場合activityRootView.getHeight()
、ソフトキーボードが表示されている天候が変わることはありません。常にアクティビティの高さとステータスバーを返します。
たとえば、Nexus 4、Android 5.0.1、android:windowTranslucentStatus
trueに設定すると、imeが開いていても1184が永久に返されます。android:windowTranslucentStatus
falseに設定すると、高さが正しく返されます。imeが非表示の場合は、1134が返されます(ステータスバーは含まれません)。imeを閉じると、5xxが返される場合があります(imeの高さに依存します)。
天気がわからないのでバグです。4.4.4と5.0.1を試してみましたが、結果は同じです。
したがって、これまで2番目に合意された答えであるカチのソリューションは、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 from を呼び出すと、 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);
}
上記の関数は、キーボードが表示されているかどうかを確認するために使用するものです。もしそうなら、私はそれを閉じます。
以下に、必要な2つの方法を示します。
まず、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;
}
}
フロッツ!
キーボードが隠されているかどうかを正確に判断できます。
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;
}
これはタブレットで機能します。ナビゲーションバーが水平に表示されている場合。