web-dev-qa-db-ja.com

ソフトキーボードが表示されると、EditTextフィールドのフォーカスが失われます

ListViewにいくつかのEditTextフィールドがあります。 EditTextフィールドの1つをタップすると、キーボードが(必要に応じて)表示されますが、タップしたEditTextフィールドはフォーカスを失います。さまざまなInputMethodManagerメソッドを使用して、キーボードをビューで開始しようとしました(実際に解決するのではなく、問題を回避するために)が、機能しませんでした-アクティビティが表示されたときにキーボードが表示されていません.

EditTextのタイプはnumberで、キーボードがスライドしているときは数字キーボードですが、スライドが終了してEditTextがフォーカスを失うと、アルファベットのキーボードに変わります(これにより、EditTextもはやフォーカスがありません)。

私の質問は次のとおりです。

1)どうすればEditTextフィールドを選択し、その後ソフトキーボードをスライドインできますかnot EditTextにフォーカスを失いますか?

...失敗した...

2)キーボードをスライドさせて表示する必要がないようにキーボードを表示するにはどうすればよいですか(したがって、好ましくない動作を回避できますか)。

私のマニフェストにはAndroid:windowSoftInputMode="stateAlwaysVisible"が、EditTextをタップするまでキーボードは表示されません。 「stateAlwaysVisible」属性のこの無視は、エミュレータでのみ発生するようです-プロビジョニングされたデバイスでは、上記の質問番号2がデバイスで動作しますが、エミュレータでは動作しません。

あなたが提供できる助けをありがとう!

52
Kyle Humfeld

これが私がやった方法です。 EditTextにタッチしてテキストを入力すると、onFocusChangeListener()が数回呼び出されます。シーケンスは次のとおりです。

  1. フォーカスが別のビューにあった場合、そのビューはフォーカスを失います
  2. ターゲットがフォーカスを獲得
  3. ソフトキーボードがポップアップします。
  4. これにより、ターゲットがフォーカスを失います
  5. コードはこの状況を検出し、target.requestFocus()を呼び出します
  6. Androidナンセンスのため、左端の最上部のビューがフォーカスを取得します
  7. RequestFocusが呼び出されるため、左端のビューがフォーカスを失います
  8. ターゲットが最終的にフォーカスを獲得

    //////////////////////////////////////////////////////////////////
    private final int minDelta = 300;           // threshold in ms
    private long focusTime = 0;                 // time of last touch
    private View focusTarget = null;
    
    View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View view, boolean hasFocus) {
            long t = System.currentTimeMillis();
            long delta = t - focusTime;
            if (hasFocus) {     // gained focus
                if (delta > minDelta) {
                    focusTime = t;
                    focusTarget = view;
                }
            }
            else {              // lost focus
                if (delta <= minDelta  &&  view == focusTarget) {
                    focusTarget.post(new Runnable() {   // reset focus to target
                        public void run() {
                            focusTarget.requestFocus();
                        }
                    });
                }
            }
        }
    };
    

上記のコードは、キーボードのポップアップに適しています。ただし、音声テキスト変換ポップアップは検出しません。

14
SoloPilot

AndroidManifest.xmlを変更する必要があります

リストビューを保持するアクティビティにAndroid:windowSoftInputMode = "adjustPan"を追加します。これで問題が解決します。

    <activity Android:name=".MyEditTextInListView"
              Android:label="@string/app_name"
              Android:windowSoftInputMode="adjustPan">

よろしく

121
Frank

私の場合、ListViewのサイズが変更されると、すべてのリストアイテムが再作成されます(つまり、表示されている各リストアイテムに対してgetView()が再度呼び出されるため)。

EditTextはgetView()から返すレイアウト内にあるため、これは以前にフォーカスがあったものとは異なるEditTextのインスタンスであることを意味します。副次的な結果として、ソフトキーボードが表示または非表示になったときに、EditTextのコンテンツが失われていることがわかりました。

ビューを完全にアクセス可能なままにしておきたい(つまり、アクセスできない一部の部分をキーボードウィンドウの後ろに隠すのではなく、サイズを変更したい)ので、フランクの答えを使用できませんでした。

EditTextでOnFocusChangeListenerを使用してフォーカスが失われたときにタイムスタンプを記録し、リスト項目を再作成するときにgetView()で現在の時刻がフォーカスが失われたときからあるしきい値内にある場合、requestFocus( )問題のEditTextに返してください。

また、その時点でEditTextの前のインスタンスからテキストを取得して、新しいインスタンスに転送することもできます。

private class MyAdapter<Type> extends ArrayAdapter<String>
    implements OnFocusChangeListener
{
    private EditText mText;
    private long mTextLostFocusTimestamp;
    private LayoutInflater mLayoutInflater;

    public MyAdapter(Context context, int resource, int textResourceId, ArrayList<String> data, LayoutInflater li) {
        super(context, resource, textResourceId, data);
        mLayoutInflater = li;
        mTextLostFocusTimestamp = -1;
    }

    private void reclaimFocus(View v, long timestamp) {
        if (timestamp == -1)
            return;
        if ((System.currentTimeMillis() - timestamp) < 250)
            v.requestFocus();
    }

    @Override public View getView (int position, View convertView, ViewGroup parent)
    {
        View v = mLayoutInflater.inflate(R.layout.mylayout, parent, false);

        EditText newText = (EditText) v.findViewById(R.id.email);
        if (mText != null)
            newText.setText(mText.getText());
        mText = newText;
        mText.setOnFocusChangeListener(this);
        reclaimFocus(mText, mTextLostFocusTimestamp);

        return v;
    }

    @Override public void onFocusChange(View v, boolean hasFocus) {
        if ((v == mText) && !hasFocus)
            mTextLostFocusTimestamp = System.currentTimeMillis();
    }
}
10
sheltond

ListView内のeditTextがgetViewメソッドでこの方法でViewを膨らませていることを確認してください。


        if (convertView == null)
        convertView = LayoutInflater.from(context).inflate(R.layout.yourItemListLayout,
                parent, false);   

編集:この作品は、一部の携帯電話では、上記のMr.Frankの回答をすべて使用しているわけではありません。

1
Samer Kador

AndroidManifest.xmlでは、ビューを含むアクティビティでadjustNothingを使用します

<activity
            Android:name=".ActivityName"
            Android:windowSoftInputMode="adjustNothing">

ハードウェアキーボードが常に表示されるデバイスでこのコードをテストする必要があります。ここでも動作が発生する場合があります。

これを回避するために、キーボードを常に表示することができます。

https://groups.google.com/forum/#!topic/Android-developers/FyENeEdmYC

理論的には、独自のAndroidキーボードを作成する必要があります(ただし、ベースとしてストックAndroidキーボード)を使用します): Android:How toキーパッドを常に表示しますか?

1
neteinstein

XamarinまたはXamarin.Formsを使用してここに来る人のために:

私も同じ問題を抱えていましたが、Android 5.x-8.1を含むすべての新しいバージョンでうまくいきました。

明らかにsheltondは正しいと言った:

私の場合、ListViewのサイズが変更されると、すべてのリストアイテムが再作成されます(つまり、表示されている各リストアイテムに対してgetView()が再度呼び出されるため)。

私のリストビューもサイズ変更されていて、いいえ、Frank s windowSoftInputMode="adjustPan"は、キーボードがリストビューを部分的に画面から移動することを意味するため、私には選択肢ではありませんでした。

数時間のフォーカスデバッグの後、Xamarin Forms ListViewのセルキャッシュ戦略を設定するだけで済みました。

から

CachingStrategy="RecycleElement"

CachingStrategy="RetainElement"

これにより、セルの再作成が停止します。ただし、これにより、巨大なリストのパフォーマンスが低下し、メモリが大量に消費される可能性があります。注意してください。

0
Waescher

リストビューまたはEditTextを保持するアクティビティにAndroid:windowSoftInputMode = "adjustResize"を追加します。これで問題が解決します。

<activity Android:name=".MainActivity"
        Android:windowSoftInputMode="adjustResize">
</activity>
0
Jibin Anto

私の場合、キーボードが表示されたときにルートScrollViewでroot_scrollview.fullScroll(View.FOCUS_DOWN)を呼び出していました。私はそれを

_login_scrollview.post(new Runnable() { 
    @Override
    public void run() {
        root_scrollview.scrollTo(0,root_container.bottom)
    }
});
_

ここで、root_containerはroot_scrollviewの直接の子です。これで問題は解決しました。

注:root_scrollview.scrollTo(0,root_container.bottom)を直接呼び出しても機能しませんでした。

0
Ismail Shaikh