web-dev-qa-db-ja.com

Androidで「仮想キーボードの表示/非表示」イベントをキャプチャする方法は?

仮想キーボードが表示されるかどうかに基づいてレイアウトを変更したいと思います。 APIとさまざまなブログを検索しましたが、有用なものが見つからないようです。

出来ますか?

ありがとう!

215
Sander Versluys

設定の変更は自分で処理する必要があります。

http://developer.Android.com/guide/topics/resources/runtime-changes.html#HandlingTheChange

サンプル:

// from the link above
@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);


    // Checks whether a hardware keyboard is available
    if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
        Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
    } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
        Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
    }
}

次に、一部のビューの可視性を変更し、フィールドを更新して、レイアウトファイルを変更します。

注意

このソリューションはソフトキーボードでは機能せず、onConfigurationChangedはソフトキーボードでは呼び出されません。

74
Pedro Loureiro

これは最も効果的な解決策ではないかもしれません。しかし、これは毎回私のために働いた...私は私がsoftKeyboardを聞く必要があるときはいつでもこの関数を呼び出します。

boolean isOpened = false;

public void setListenerToRootView() {
    final View activityRootView = getWindow().getDecorView().findViewById(Android.R.id.content);
    activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
            if (heightDiff > 100) { // 99% of the time the height diff will be due to a keyboard.
                Toast.makeText(getApplicationContext(), "Gotcha!!! softKeyboardup", 0).show();

                if (isOpened == false) {
                    //Do two things, make the view top visible and the editText smaller
                }
                isOpened = true;
            } else if (isOpened == true) {
                Toast.makeText(getApplicationContext(), "softkeyborad Down!!!", 0).show();
                isOpened = false;
            }
        }
    });
}

注:ユーザーがフローティングキーボードを使用している場合、この方法では問題が発生します。

54
amalBit

アクティビティからIMM(仮想)キーボードウィンドウの表示/非表示を処理する場合、レイアウトをサブクラス化し、onMesureメソッドをオーバーライドする必要があります(レイアウトの測定幅と測定高さを決定できるように)。その後、setContentView()によってアクティビティのメインビューとしてサブクラス化されたレイアウトを設定します。これで、IMMウィンドウの表示/非表示イベントを処理できるようになります。これが複雑に聞こえる場合、それは実際にはありません。コードは次のとおりです。

main.xml

   <?xml version="1.0" encoding="utf-8"?>
   <LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent"
        Android:orientation="horizontal" >
        <EditText
             Android:id="@+id/SearchText" 
             Android:text="" 
             Android:inputType="text"
             Android:layout_width="fill_parent"
             Android:layout_height="34dip"
             Android:singleLine="True"
             />
        <Button
             Android:id="@+id/Search" 
             Android:layout_width="60dip"
             Android:layout_height="34dip"
             Android:gravity = "center"
             />
    </LinearLayout>

アクティビティ内で、レイアウトのサブクラスを宣言します(main.xml)

    public class MainSearchLayout extends LinearLayout {

    public MainSearchLayout(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.main, this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d("Search Layout", "Handling Keyboard Window shown");

        final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
        final int actualHeight = getHeight();

        if (actualHeight > proposedheight){
            // Keyboard is shown

        } else {
            // Keyboard is hidden
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

コードから、サブクラスコンストラクターのアクティビティのレイアウトを膨らませていることがわかります。

inflater.inflate(R.layout.main, this);

そして、アクティビティのサブクラスレイアウトのコンテンツビューを設定するだけです。

public class MainActivity extends Activity {

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        MainSearchLayout searchLayout = new MainSearchLayout(this, null);

        setContentView(searchLayout);
    }

    // rest of the Activity code and subclassed layout...

}
37
Nebojsa Tomcic

私はこのようにしました:

OnKeyboardVisibilityListenerインターフェイスを追加します。

public interface OnKeyboardVisibilityListener {
    void onVisibilityChanged(boolean visible);
}

HomeActivity.Java

public class HomeActivity extends Activity implements OnKeyboardVisibilityListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sign_up);
    // Other stuff...
    setKeyboardVisibilityListener(this);
}

private void setKeyboardVisibilityListener(final OnKeyboardVisibilityListener onKeyboardVisibilityListener) {
    final View parentView = ((ViewGroup) findViewById(Android.R.id.content)).getChildAt(0);
    parentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        private boolean alreadyOpen;
        private final int defaultKeyboardHeightDP = 100;
        private final int EstimatedKeyboardDP = defaultKeyboardHeightDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Lollipop ? 48 : 0);
        private final Rect rect = new Rect();

        @Override
        public void onGlobalLayout() {
            int estimatedKeyboardHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, parentView.getResources().getDisplayMetrics());
            parentView.getWindowVisibleDisplayFrame(rect);
            int heightDiff = parentView.getRootView().getHeight() - (rect.bottom - rect.top);
            boolean isShown = heightDiff >= estimatedKeyboardHeight;

            if (isShown == alreadyOpen) {
                Log.i("Keyboard state", "Ignoring global layout change...");
                return;
            }
            alreadyOpen = isShown;
            onKeyboardVisibilityListener.onVisibilityChanged(isShown);
        }
    });
}


@Override
public void onVisibilityChanged(boolean visible) {
    Toast.makeText(HomeActivity.this, visible ? "Keyboard is active" : "Keyboard is Inactive", Toast.LENGTH_SHORT).show();
  }
}

これがあなたのお役に立てば幸いです。

24
Hiren Patel

Nebojsa Tomcicのコードに基づいて、次のRelativeLayout-Subclassを開発しました。

import Java.util.ArrayList;

import Android.content.Context;
import Android.util.AttributeSet;
import Android.widget.RelativeLayout;

public class KeyboardDetectorRelativeLayout extends RelativeLayout {

    public interface IKeyboardChanged {
        void onKeyboardShown();
        void onKeyboardHidden();
    }

    private ArrayList<IKeyboardChanged> keyboardListener = new ArrayList<IKeyboardChanged>();

    public KeyboardDetectorRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

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

    public KeyboardDetectorRelativeLayout(Context context) {
        super(context);
    }

    public void addKeyboardStateChangedListener(IKeyboardChanged listener) {
        keyboardListener.add(listener);
    }

    public void removeKeyboardStateChangedListener(IKeyboardChanged listener) {
        keyboardListener.remove(listener);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
        final int actualHeight = getHeight();

        if (actualHeight > proposedheight) {
            notifyKeyboardShown();
        } else if (actualHeight < proposedheight) {
            notifyKeyboardHidden();
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void notifyKeyboardHidden() {
        for (IKeyboardChanged listener : keyboardListener) {
            listener.onKeyboardHidden();
        }
    }

    private void notifyKeyboardShown() {
        for (IKeyboardChanged listener : keyboardListener) {
            listener.onKeyboardShown();
        }
    }

}

これは非常にうまく機能します...マーク、アクティビティのソフト入力モードが「WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE」に設定されている場合にのみこのソリューションが機能すること

22
Stefan

@amalBitの答えのように、リスナーをグローバルレイアウトに登録し、dectorViewの可視ボトムと提案ボトムの差を計算します。差が特定の値(IMEの高さを推測)よりも大きい場合、IMEはアップしていると考えます。

    final EditText edit = (EditText) findViewById(R.id.edittext);
    edit.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if (keyboardShown(edit.getRootView())) {
                Log.d("keyboard", "keyboard UP");
            } else {
                Log.d("keyboard", "keyboard Down");
            }
        }
    });

private boolean keyboardShown(View rootView) {

    final int softKeyboardHeight = 100;
    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    int heightDiff = rootView.getBottom() - r.bottom;
    return heightDiff > softKeyboardHeight * dm.density;
}

高さのしきい値100は、IMEの推測される最小の高さです。

これはadjustPanとadjustResizeの両方で機能します。

19
alexhilton

Nebojsaのソリューションは私にとってはほとんど機能しました。複数行のEditText内をクリックすると、キーボードが表示されることがわかりましたが、EditText内で入力を開始したとき、実際の高さと提案された高さは同じであったため、キーボードが表示されていることがわかりませんでした。最大の高さを保存するためにわずかな変更を加えましたが、正常に機能します。改訂されたサブクラスは次のとおりです。

public class CheckinLayout extends RelativeLayout {

    private int largestHeight;

    public CheckinLayout(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.checkin, this);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
        largestHeight = Math.max(largestHeight, getHeight());

        if (largestHeight > proposedheight)
            // Keyboard is shown
        else
            // Keyboard is hidden

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
12
Gary Foster

これを解決するには、カスタムEditTextでonKeyPreIme(int keyCode、KeyEvent event)をオーバーライドします。

@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
        //keyboard will be hidden
    }
}
10
qbait

誰かがこれを投稿するかどうかわからない。見つかりました このソリューションは使いやすい!SoftKeyboardクラスはGist.github.comにあります 。ただし、キーボードのポップアップ/非表示イベントコールバックでは、UIで適切に処理するためのハンドラーが必要です。

/*
Somewhere else in your code
*/
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use your root layout
InputMethodManager im = (InputMethodManager) getSystemService(Service.INPUT_METHOD_SERVICE);

/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged()
{

    @Override
    public void onSoftKeyboardHide() 
    {
        // Code here
        new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    // Code here will run in UI thread
                    ...
                }
            });
    }

    @Override
    public void onSoftKeyboardShow() 
    {
        // Code here
        new Handler(Looper.getMainLooper()).post(new Runnable() {
                @Override
                public void run() {
                    // Code here will run in UI thread
                    ...
                }
            });

    }   
});
10
Robert

これを行うためのハッキングがあります。ソフトキーボードが表示または非表示になったことを検出する方法はないようですが、実際にはcanが表示されているか、非表示になっていることを検出しますabout聞いているOnFocusChangeListenername__にEditTextname__を設定します。

EditText et = (EditText) findViewById(R.id.et);
et.setOnFocusChangeListener(new View.OnFocusChangeListener()
    {
        @Override
        public void onFocusChange(View view, boolean hasFocus)
        {
            //hasFocus tells us whether soft keyboard is about to show
        }
    });

注:このハックで注意すべきことの1つは、EditTextname__がフォーカスを取得または失うと、このコールバックがすぐに起動されることです。これは実際に起動します直前ソフトキーボードが表示または非表示になります。 afterキーボードを表示または非表示にするために私が見つけた最良の方法は、Handlername__を使用し、何かを約400ミリ秒遅らせることです。

EditText et = (EditText) findViewById(R.id.et);
et.setOnFocusChangeListener(new View.OnFocusChangeListener()
    {
        @Override
        public void onFocusChange(View view, boolean hasFocus)
        {
            new Handler().postDelayed(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        //do work here
                    }
                }, 400);
        }
    });
4
poisondminds

サンダー、私はあなたがソフトキーボードによってブロックされたビューを表示しようとしていると信じています。これを試してください http://Android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html

3
100rabh

私は単一行のtextviewバックコーディングの問題を解決しました。

package com.helpingdoc;

import Android.content.Context;
import Android.util.AttributeSet;
import Android.util.Log;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.widget.LinearLayout;

public class MainSearchLayout extends LinearLayout {
    int hieght = 0;
    public MainSearchLayout(Context context, AttributeSet attributeSet) {

        super(context, attributeSet);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.main, this);


    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d("Search Layout", "Handling Keyboard Window shown");
       if(getHeight()>hieght){
           hieght = getHeight();
       }
        final int proposedheight = MeasureSpec.getSize(heightMeasureSpec);
        final int actualHeight = getHeight();
        System.out.println("....hieght = "+ hieght);
        System.out.println("....actualhieght = "+ actualHeight);
        System.out.println("....proposedheight = "+ proposedheight);
        if (actualHeight > proposedheight){
            // Keyboard is shown


        } else if(actualHeight<proposedheight){
            // Keyboard is hidden

        }

        if(proposedheight == hieght){
             // Keyboard is hidden
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
2
user2462737

最初のDecorViewの子の下部パディングを確認することもできます。キーボードが表示されると、ゼロ以外の値に設定されます。

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    View view = getRootView();
    if (view != null && (view = ((ViewGroup) view).getChildAt(0)) != null) {
        setKeyboardVisible(view.getPaddingBottom() > 0);
    }
    super.onLayout(changed, left, top, right, bottom);
}
2
MatrixDev

非表示|キーボードのイベントを表示するには、OnGlobalLayoutListenerの単純なハックを使用します。

 final View activityRootView = findViewById(R.id.top_root);
        activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();

                if (heightDiff > 100) {
                    // keyboard is up
                } else {
                    // keyboard is down
                }
            }
        });

ここで、activityRootViewはアクティビティのルートビューです。

0
Varun Verma