【質問】ソフトウェアキーボード収納の検知方法

6,950 views
Skip to first unread message

nekochan

unread,
May 19, 2011, 9:27:24 PM5/19/11
to 日本Androidの会
nekochanと申します。

標記、非常によくある種類の質問で、検索するとたくさん方法が出てくるのですが、
どうにもその通りに行かず、悩んでおります。
どの方法も、これじゃうまくいかないよ、という記事は見あたらないので
おそらく何かこちらの見落とし等だと思うのですが・・・お気づきの点ありましたらご指摘ください。

目的としては、表示系が若干特殊なため pan-scan処理を自前で行わねばならず、
そのため、「ソフトウェアキーボードの収納を検知→元の位置へのスクロールを実行」
というのを手動で行いたい、というものです。
とりあえずこちらで試した方法は以下のものです。

(1)端末の戻るボタンのフック
 1-a) onBackPressedのオーバーライド
 1-b) onKeyDown / onKeyUpのオーバーライド
 1-c) dispatchKeyEventのオーバーライド
いずれも、ソフトウェアキーボードの方でイベントが消化されてしまい、
Activityの方に下りてこないようです。

(2)リサイズの検知
 1-a) 各ビューの onSizeChangedをオーバーライド
 2-b) FrameLayoutを継承したMyFrameLayoutを作り、
   onSizeChangedをオーバーライド、それを setContentViewして使用
※いずれも、AndroidManifestに adjustResizeを指定しています。
どちらもonSizeChangedが呼ばれていないようです。

ちなみに当方の検証端末は IS03, Galaxy S と SDK付属エミュレータです。


それでは失礼します。

大垣憲俊

unread,
May 19, 2011, 9:49:31 PM5/19/11
to android-g...@googlegroups.com
ねこちゃん様

大垣です。私も開発中のアプリで同様の現象に遭遇しました。

参考にはならないかもしれませんが、私のとった解決策は、
入力テキスト領域の OnKeyListener において、エンターキーの入力を検出した場合に
以下のメソッドを呼ぶ、というものです。

private void hideKeyboard() {

InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);

imm.hideSoftInputFromWindow(labelText.getWindowToken(), 0);

}


申し上げたかったのは、通常予想しうるイベントが捕捉できない場合、
(もう開き直って)何らかのイベントを起こして捕捉する、というアイデアだということです。

大垣憲俊

unread,
May 19, 2011, 9:55:03 PM5/19/11
to android-g...@googlegroups.com
ねこちゃん様

大垣です。自己レスです。

どうも外してしまいました。
キーボード収納のイベントを捕捉したいというご主旨でしたね。
すみません、忘れてください。

nekochan

unread,
May 19, 2011, 10:21:39 PM5/19/11
to 日本Androidの会
大垣様、

返信ありがとうございます!

イベント起こして補足、という考え方を何か発想の転換で利用できないかな・・・
と思いました。
検討の材料をありがとうございます*

mokkouyou

unread,
May 19, 2011, 11:09:21 PM5/19/11
to android-g...@googlegroups.com
mokkouyouです。

ちょっとだけ気になったので。
activityにandroid:configChangesでkeyboardHidden
とか指定してやるとキーボードの開閉とのタイミングでonConfigurationChangedがよばれたと思いますが・・・試されました?
ソフトウェアキーボードの場合は取れないとかあったんでしたっけ?
試す時間も環境も気力もないのでキーワードだけですが。

以上よろしくお願いいたします。

noritoshi ogaki

unread,
May 20, 2011, 12:04:33 AM5/20/11
to android-g...@googlegroups.com
mokkouyou様

大垣です。

>activityにandroid:configChangesでkeyboardHidden
>とか指定してやるとキーボードの開閉とのタイミングで
>onConfigurationChangedがよばれたと思いますが・・・試されました?

はい、試しました。"keyboardHidden"でも"keyboard"でも
onConfigurationChanged は呼ばれないみたいですね。

>ソフトウェアキーボードの場合は取れないとかあったんでしたっけ?

リファレンスを見ると、想定しているのは外部キーボードのようですね。

"keyboard" ... キーボードが変更された。例えば、ユーザが外部キーボードを差し込んだ場合。
"keyboardHidden" ... キーボードのアクセシビリティが変更された。例えば、ユーザがキーボードを外に引き出した。


2011年5月20日12:09 mokkouyou <mokk...@gmail.com>:

nekochan

unread,
May 20, 2011, 2:28:00 AM5/20/11
to 日本Androidの会
mokkouyou様、大垣様、

mokkouyouさんの案、後で試してみようと思ってましたが、
大垣さんがすでに試されていたのですね;

onConfigurationChangedは外部キーボードですか。
確かに名称的にもデバイス系の話っぽいですしね;


となると・・・あとは画面サイズ(onSizeChanged)の方でなんとかならないかな、というところでしょうか。
ここのやりとりによるとどうも onSizeChangedも一筋縄ではいかないようですが、どうなのでしょうか・・・。
http://www.mail-archive.com/android-d...@googlegroups.com/msg92529.html



On 5月20日, 午後1:04, noritoshi ogaki <noritoshi.og...@gmail.com> wrote:
> mokkouyou様
>
> 大垣です。
>
> >activityにandroid:configChangesでkeyboardHidden
> >とか指定してやるとキーボードの開閉とのタイミングで
> >onConfigurationChangedがよばれたと思いますが・・・試されました?
>
> はい、試しました。"keyboardHidden"でも"keyboard"でも
> onConfigurationChanged は呼ばれないみたいですね。
>
> >ソフトウェアキーボードの場合は取れないとかあったんでしたっけ?
>
> リファレンスを見ると、想定しているのは外部キーボードのようですね。
>
> "keyboard" ... キーボードが変更された。例えば、ユーザが外部キーボードを差し込んだ場合。
> "keyboardHidden" ... キーボードのアクセシビリティが変更された。例えば、ユーザがキーボードを外に引き出した。
>
> 2011年5月20日12:09 mokkouyou <mokkou...@gmail.com>:

大垣憲俊

unread,
May 20, 2011, 2:47:53 AM5/20/11
to 日本Androidの会
大垣です。

そもそも。ソフトキーボードが表示されているかどうかを知るのは
これでしたっけ?

InputMethodManager mgr = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(hogehogeText.getWindowToken(), 0);
if (mgr.isActive()) {
// ...

これを onSizeChanged() で試すといいですね。


あと、女子部の副部長さん? です。

Y.A.M の 雑記帳: Android SearchManager ソフトキーボードを消すぜ!
http://y-anz-m.blogspot.com/2010/03/android-searchmanager_08.html

Android ボタンを押したときにソフトキーボードを消す
http://y-anz-m.blogspot.com/2009/12/android.html


私の最初の返信と同じ発想のような気がします。


On 5月20日, 午後3:28, nekochan <y...@pc4.so-net.ne.jp> wrote:
> mokkouyou様、大垣様、
>
> mokkouyouさんの案、後で試してみようと思ってましたが、
> 大垣さんがすでに試されていたのですね;
>
> onConfigurationChangedは外部キーボードですか。
> 確かに名称的にもデバイス系の話っぽいですしね;
>
> となると・・・あとは画面サイズ(onSizeChanged)の方でなんとかならないかな、というところでしょうか。
> ここのやりとりによるとどうも onSizeChangedも一筋縄ではいかないようですが、どうなのでしょうか・・・。http://www.mail-archive.com/android-d...@googlegroups.com/msg92...

大垣憲俊

unread,
May 20, 2011, 2:50:29 AM5/20/11
to 日本Androidの会
大垣です。すみません、手元がすべってミスしました。
> InputMethodManager mgr = (InputMethodManager)
> getSystemService(Context.INPUT_METHOD_SERVICE);
//mgr.hideSoftInputFromWindow(hogehogeText.getWindowToken(), 0);
//上のはキーボード隠す、下のがキーボード表示しているかどうか、かな?
> if (mgr.isActive()) {
> // ...


On 5月20日, 午後3:47, 大垣憲俊 <noritoshi.og...@gmail.com> wrote:
> 大垣です。
>
> そもそも。ソフトキーボードが表示されているかどうかを知るのは
> これでしたっけ?
>
> InputMethodManager mgr = (InputMethodManager)
> getSystemService(Context.INPUT_METHOD_SERVICE);
> mgr.hideSoftInputFromWindow(hogehogeText.getWindowToken(), 0);
> if (mgr.isActive()) {
> // ...
>
> これを onSizeChanged() で試すといいですね。
>
> あと、女子部の副部長さん? です。
>
> Y.A.M の 雑記帳: Android SearchManager ソフトキーボードを消すぜ!http://y-anz-m.blogspot.com/2010/03/android-searchmanager_08.html
>
> Android ボタンを押したときにソフトキーボードを消すhttp://y-anz-m.blogspot.com/2009/12/android.html

mokkouyou

unread,
May 20, 2011, 4:46:06 AM5/20/11
to android-g...@googlegroups.com

mokkouyouです。
adjustResizeとの組み合わせでも駄目でしたか、、、

自分で出すIMEなら、引数でResultReceiverなんて使えそうなインスタンス渡せるみたいなんですけどね。(名前的にですけど。)

こいつが使えるようなら全ての入力系を自前で、、、ってのは数にもよるけど非現実的だったりしますよね(+_+)

nekochan

unread,
May 20, 2011, 6:33:01 AM5/20/11
to 日本Androidの会
nekochanです。

>大垣様
isActive(View view)の挙動を調べてみたのですが、viewがインプットメソッドに紐付いているかを調べるもののようで、キーボード
の表示・非表示とは関係ないようです;
複数の TextEdit がある場合に、自分んとこがインプットの受け取り手になってるか?を判別する等に使うっぽいですね。

ちなみに、引数無しの isActive() だと、どれかのビューに紐付いていれば true なので、明示的にすべての紐付けを外さなければ常に
true が返ってくる感じです。(おそらく)

>mokkouyou様
自分でリンク張った記事をもう一回読んでみたのですが、Activityに Theme.NoTitleBar.Fullscreen が指定してある
と onSizeChanged が呼ばれないようです。
実際、Fullscreen 指定を外したら、ちゃんと onSizeChanged が呼ばれました。

でも思いっきりデザインありきで進んでるアプリなので、今さらステータスバー表示でいいっすか?とはとても言えないのが悲しいところです・・・;

noritoshi ogaki

unread,
May 20, 2011, 6:47:30 AM5/20/11
to android-g...@googlegroups.com
ねこちゃんさん

大垣です.

> isActive(View view)の挙動を調べてみたのですが、viewがインプットメソッドに紐付いているかを


> 調べるもののようで、キーボード
> の表示・非表示とは関係ないようです;
> 複数の TextEdit がある場合に、自分んとこがインプットの受け取り手になってるか?を
> 判別する等に使うっぽいですね。

てきとうなことを言ってお手数をおかけしてしまい、どうもすみませんでした。
ちょっと責任を感じて、InputMethod関係のソースコードを確認中です。。。

大垣憲俊

unread,
May 20, 2011, 7:38:50 AM5/20/11
to 日本Androidの会
ねこちゃんさん

大垣です。 ちょっと確認したいことが。

画面レイアウトとしては、EditTextがあって、
そこでインプットメソッドを使うという想定ですよね、それは当然。

そこのEditTextに設定できると仮定して、
ソフトキーボードの Done ボタンに任意のアクションを追加する、
という方法があるのですが。これで問題を回避できるかな、と。

キーボードの決定ボタン - imeOptions (EditText)
http://michelle-gf.blogspot.com/2011/03/imeoptions-edittext.html


ついでに言うと、思いつきで、InputMethodService にバインドして、
finishを受信できるのかなぁと妄想しています。

nekochan

unread,
May 20, 2011, 7:52:59 AM5/20/11
to 日本Androidの会
実は、ここが悩ましいところで、
複数行入力を行いたいので、エンターキーは改行のために
とっておかないといけないのです;

キーをもう一個追加、とかできたらいいんですが;


On 5月20日, 午後8:38, 大垣憲俊 <noritoshi.og...@gmail.com> wrote:
> ねこちゃんさん
>
> 大垣です。 ちょっと確認したいことが。
>
> 画面レイアウトとしては、EditTextがあって、
> そこでインプットメソッドを使うという想定ですよね、それは当然。
>
> そこのEditTextに設定できると仮定して、
> ソフトキーボードの Done ボタンに任意のアクションを追加する、
> という方法があるのですが。これで問題を回避できるかな、と。
>
> キーボードの決定ボタン - imeOptions (EditText)http://michelle-gf.blogspot.com/2011/03/imeoptions-edittext.html

大垣憲俊

unread,
May 20, 2011, 1:58:01 PM5/20/11
to 日本Androidの会
大垣です。

その後あれこれと試したわりに何も進展がないのですが、
もう少し調べたいと思います。

大垣憲俊

unread,
May 21, 2011, 3:03:49 AM5/21/11
to 日本Androidの会
大垣です。

> > > ついでに言うと、思いつきで、InputMethodService にバインドして、
> > > finishを受信できるのかなぁと妄想しています。

この件、まだ試しているところですが、
com.android.internal.view.IInputMethod* を使わざるをえず、
自分で言っておきながら恐縮ですが、たいして良い方法とは思えません。

それで、やはり入力終了のボタンなどを追加して、そのクリックイベントで復帰するのが
良いのではないかというのが、私の(諦めた?)結論です。

私の場合は、EditText内での改行をさせないことにして、改行によって次のアクションとしていました。
この問題に気づいた時点でこうした解決策を取らずにいれば、
今回の nekochanさんの問題にアドバイスができたかも、と、くやしい気持ちです。

それと、もう1つ失敗事例を残しておくのも意義がありそうな気がするので書き添えます。

試したのは、ViewTreeObserver でレイアウトの変化をつかむ方法です。
しかし、ソフトキーボードによるレイアウトの変化とは無関係でした。
以下のようなコーディングです。

final EditText text1 = (EditText) findViewById(R.id.text1);
final View decor = getWindow().getDecorView();
final ViewGroup frame = (ViewGroup)
decor.findViewById(android.R.id.content);
ViewTreeObserver vto = frame.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Log.d(TAG, "onGlobalLayout()");
int count = frame.getChildCount();
for (int i = 0; i < count; i++) {
Log.d(TAG, "child[" + i + "]=" +
frame.getChildAt(i).getId());
final ViewGroup child2 = (ViewGroup)
frame.getChildAt(i);
int count2 = child2.getChildCount();
for (int j = 0; j < count2; j++) {
Log.d(TAG, "child[" + i + "]_child[" + j +
"]="
+ child2.getChildAt(j).getId());
if (child2.getChildAt(j) instanceof ViewGroup)
{
final ViewGroup child3 = (ViewGroup)
child2.getChildAt(j);
int count3 = child3.getChildCount();
for (int k = 0; k < count3; k++) {
Log.d(TAG, "child[" + i + "," + j +
"," + k + "]="
+
child3.getChildAt(j).getId());
}
}
}
}
}
});
---

ということで、お役に立てず申し訳ありません。

doralos alen

unread,
May 21, 2011, 8:15:40 AM5/21/11
to android-g...@googlegroups.com
alendoralosです



    private StateListener listener;

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

    public interface StateListener {
        void onShow();

        void onHide();
    }

    public void setOnStateChange(StateListener listener) {
        this.listener = listener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        Activity a = (Activity) getContext();
        Rect rect = new Rect();
        a.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        int visible = rect.bottom - rect.top;
        int display = a.getWindowManager().getDefaultDisplay().getHeight();
        int space = display - visible;

        if (listener != null) {

            if (space > 130) {

                listener.onShow();

            } else {
                listener.onHide();
            }

        }

    }

2011年5月21日15:03 大垣憲俊 <noritos...@gmail.com>:

--
このメールは Google グループのグループ「日本Androidの会」の登録者に送られています。
このグループに投稿するには、android-g...@googlegroups.com にメールを送信してください。
このグループから退会するには、android-group-j...@googlegroups.com にメールを送信してください。
詳細については、http://groups.google.com/group/android-group-japan?hl=ja からこのグループにアクセスしてください。


noritoshi ogaki

unread,
May 21, 2011, 9:22:29 AM5/21/11
to android-g...@googlegroups.com
alendoralosさん

大垣です。ご登場のしかたが、なんか、かっこいいです。

int visible = rect.bottom - rect.top;
int display = a.getWindowManager().getDefaultDisplay().getHeight();
int space = display - visible;

if (space > 130) {

このDefaultDisplayの高さとWindowVisibleDisplayFrameの高さの差が
130 以上なら、という部分ですね。
できれば、130の意味が分かっておきたいかも。。。


2011年5月21日21:15 doralos alen <alend...@gmail.com>:

nekochan

unread,
May 21, 2011, 2:39:57 PM5/21/11
to 日本Androidの会
大垣さん、alendoralosさん

なんだかオオゴトになってきてしまって申し訳ないです;
いろいろな切り口が出てきて勉強になります!

検知の方法として stateChange というのもあるのですね。
加えて、visibleな範囲というのが別途取れると。

今日はちょっと遅くなってしまったので試せないですが、
明日にでも試してみようと思います!



On 5月21日, 午後10:22, noritoshi ogaki <noritoshi.og...@gmail.com> wrote:
> alendoralosさん
>
> 大垣です。ご登場のしかたが、なんか、かっこいいです。
>
> int visible = rect.bottom - rect.top;
> int display = a.getWindowManager().getDefaultDisplay().getHeight();
> int space = display - visible;
> if (space > 130) {
>
> このDefaultDisplayの高さとWindowVisibleDisplayFrameの高さの差が
> 130 以上なら、という部分ですね。
> できれば、130の意味が分かっておきたいかも。。。
>
> 2011年5月21日21:15 doralos alen <alendora...@gmail.com>:

doralos alen

unread,
May 22, 2011, 2:15:43 AM5/22/11
to android-g...@googlegroups.com
大垣さん
alendoralosです。softkeyboardの高さが130px以上と思っています。

2011年5月22日2:39 nekochan <yo...@pc4.so-net.ne.jp>:

noritoshi ogaki

unread,
May 22, 2011, 4:39:41 AM5/22/11
to android-g...@googlegroups.com
alendoralosさん

大垣です。ありがとうございます。

> softkeyboardの高さが130px以上と思っています。

はい、そのことが気になっていて、ソフトキーボードの高さって
端末とユーザによって異なるのではないかと。
たとえば、1行キーボードの人もいるかも?

すみません、細かいことであげあしとる気はないのですけど。。。

大垣憲俊

unread,
May 22, 2011, 10:48:41 AM5/22/11
to 日本Androidの会
大垣です。

追加で申し上げておきます。

現在使用中のキーボードの高さを R.dimenから取得できたとしても、
もう1つ気がかりなのは、その画面の高さの違いが、
ソフトキーボードによるものと決めてしまっていいものかどうか。

つまり、現在のところはソフトキーボード以外に画面サイズが縦に変わるものがないとしても、
OSのバージョンアップやアプリの機能などにより、ソフトキーボード以外の要因で、
画面の高さが変わることがあるかもしれない、という懸念です。

nekochan

unread,
May 24, 2011, 12:44:35 AM5/24/11
to 日本Androidの会
みなさま

nekochanです。

こちらでの検討の経緯をアプリの依頼主に説明したところ、"そんなに難しいならあきらめます" ということになりまして、結局未解決のまま行くというこ
とに相成りました;
いろいろとアドバイスをくださったみなさん申し訳ありません。

しかし、おかげさまでソフトウェアキーボード周りの挙動について詳しく知ることができたので、今後のプロジェクトに役立てたいと思います。
ありがとうございました!
Reply all
Reply to author
Forward
0 new messages