ソフトキーボードの表示を検知してレイアウトを変更する
入力時にはEditTextにフォーカスがあたりソフトキーボードが起動しますが、その挙動に影響されて、以下のようにEditTextがつぶれて使いづらくなることがあります。意外とリリースされてるソフトでも結構見かけます。
こういうレイアウトで、
文字入力しようとすると…あらら
変換候補が表示されたあかつきには…ぐぬぬー
対処方法
このような場合、色々な対処法がありますが、ソフトキーボードの表示/非表示を検知してレイアウトを変えるというのも一つの手です。現状ソフトキーボードの表示/非表示を検知するようなAPIはありません。一般的にはカスタムViewを作成しその縦幅からソフトキーボードの表示/非表示を判断し、レイアウトを変更するのが通例のようです。意外と簡単なのでココにメモします。
構成
- /src/org/superdry/sample/gui/DetectableSoftKeyLayout.java
- カスタムレイアウトクラス
- /src/org/superdry/sample/gui/MainActivity.java
- 起動Activity
- /res/layout/main.xml
- MainActivityのレイアウトxml
- AndroidManifest.xml
DetectableSoftKeyLayout.java
今回はLinearLayoutを拡張し、カスタムレイアウトを作成しました。このレイアウトの縦幅を監視するリスナーを実装します。ここでは例として、ソフトキーボードの表示によってLinearLayoutの縦幅100px縮んだ場合、ソフトキーボードが表示されているとして、onSoftKeyShownにtrueをセットしてます。
package org.superdry.sample.gui; import android.app.Activity; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.widget.LinearLayout; public class DetectableSoftKeyLayout extends LinearLayout { public DetectableSoftKeyLayout(Context context, AttributeSet attrs) { super(context, attrs); } public interface OnSoftKeyShownListener { public void onSoftKeyShown(boolean isShown); } private OnSoftKeyShownListener listener; public void setListener(OnSoftKeyShownListener listener) { this.listener = listener; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // (a)Viewの高さ int viewHeight = MeasureSpec.getSize(heightMeasureSpec); // (b)ステータスバーの高さ Activity activity = (Activity) getContext(); Rect rect = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect); int statusBarHeight = rect.top; // (c)ディスプレイサイズ int screenHeight = activity.getWindowManager().getDefaultDisplay() .getHeight(); // (a)-(b)-(c)>100ピクセルとなったらソフトキーボードが表示されてると判断 //(ソフトキーボードはどんなものでも最低100ピクセルあると仮定) int diff = (screenHeight - statusBarHeight) - viewHeight; if (listener != null) { listener.onSoftKeyShown(diff > 100); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
MainActivity.java
ここではリスナーの登録と、ソフトキーボードが表示の場合/非表示の場合の処理を実装しています。ここでは例としてソフトキーボード表示の場合はPostボタンを非表示にしています。
package org.superdry.sample.gui; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import org.superdry.sample.gui.R; public class MainActivity extends Activity { private Button post; private DetectableSoftKeyLayout layout; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); layout = (DetectableSoftKeyLayout) findViewById(R.id.detectable_layout); layout.setListener(listner); post = (Button) findViewById(R.id.post_btn); } DetectableSoftKeyLayout.OnSoftKeyShownListener listner = new DetectableSoftKeyLayout.OnSoftKeyShownListener() { @Override public void onSoftKeyShown(boolean isShown) { if (isShown) { // ソフトキーボードが表示されている場合 // postボタンを非表示にする post.setVisibility(View.GONE); } else { // ソフトキーボードが表示されてなければ、表示する post.setVisibility(View.VISIBLE); } } }; }
main.xml
MainActivityのレイアウトファイルです。
<?xml version="1.0" encoding="utf-8"?> <org.superdry.sample.gui.DetectableSoftKeyLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:orientation="vertical" android:layout_height="match_parent" android:id="@+id/detectable_layout"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Input Message" android:textSize="20dp"/> <EditText android:id="@+id/edittext" android:inputType="textMultiLine" android:layout_height="match_parent" android:layout_width="match_parent" android:layout_weight="1"> </EditText> <Button android:text="Post" android:id="@+id/post_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" > <requestFocus /></Button> </org.superdry.sample.gui.DetectableSoftKeyLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.superdry.sample.gui" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="4" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name="org.superdry.sample.gui.MainActivity" android:label="@string/app_name" android:windowSoftInputMode="adjustResize"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>