android EditText-入力完了イベント


122

ユーザーがEditTextの編集を完了したときにイベントをキャッチしたい。

どうすればできますか?


1
@PadmaKumar最も自然な方法は、EditTextでフォーカスが失われた場合です。その後、ユーザーは間違いなく完了しますが、経験から、すべてのAndroidウィジェットが適切にフォーカスを取得しているわけではないようです(スピナーとボタンに問題があった)-そのため、他のウィジェットがフォーカスを失う可能性はありません...
AgentKnopf、2012

3
なぜこのような大きなプラットフォームで、この種の単純な関数を処理できるのでしょうか。そのような主要機能をサポートライブラリに少なくとも追加しても、グーグルは何も失うことはありません
MBH

ユーザーが入力する文字列の正確な長さがわかっている場合は、afterTextChangedでテキストを取得します。例:override fun afterTextChanged(s: Editable?) { if (s.toString().length == 5) { val enteredString = s.toString() }
Shylendra Madda

2
Androidでこれがなぜ難しいのか、私(自分も含めて)がオンラインディスカッションと10行以上のコードを使用したさまざまなソリューションを検索して開始する必要があるのか​​と不思議に思っています。
nsandersen

回答:


119

ユーザーが編集を終えたら、Doneまたはを押すEnter

((EditText)findViewById(R.id.youredittext)).setOnEditorActionListener(
    new EditText.OnEditorActionListener() {
        @Override
        public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
            if (actionId == EditorInfo.IME_ACTION_SEARCH ||
                    actionId == EditorInfo.IME_ACTION_DONE ||
                    event != null &&
                    event.getAction() == KeyEvent.ACTION_DOWN &&
                    event.getKeyCode() == KeyEvent.KEYCODE_ENTER) {
                if (event == null || !event.isShiftPressed()) {
                   // the user is done typing. 

                   return true; // consume.
                }                
            }
            return false; // pass on to other listeners. 
        }
    }
);

50
あなたはそれについて確信がありますか?私は次の編集可能なフィールドに出入りする癖があります-Enter / Doneを押すことはほとんどありません-私が顧客から見たことも、彼らもそうではありません... Edittexts / Comboboxesのリストなどについて話している。ユーザーに入力フィールドを1つだけ与え、ユーザーが他のフィールドに進む前にボタンを押すように強制する場合、それは明らかに別の話です...
AgentKnopf

5
また、編集テキストにはandroid:singleLine = "true"を設定する必要があります。stackoverflow.com/questions/15901863/…の
スティーブンスミス

1
良い解決策ですが、nullポインターでクラッシュする可能性があります... Doneアクションで 'event'がnullになる可能性があるため、event.isShiftPressed()がクラッシュします。これを使用する場合は、ヌルポインターチェックを追加してください。
ジョージー

nullの「イベント」をチェックするための編集が追加されました。
ワード

3
キーボードを閉じる[戻る]ボタンを押すとどうなりますか?
user347187

183

より良い方法は、EditText onFocusChangeリスナーを使用して、ユーザーが編集を完了したかどうかを確認することもできますユーザーがソフトキーボードの[完了]ボタンまたは[Enter]ボタンを押す必要はありません)。

 ((EditText)findViewById(R.id.youredittext)).setOnFocusChangeListener(new OnFocusChangeListener() {

    @Override
    public void onFocusChange(View v, boolean hasFocus) {

      // When focus is lost check that the text field has valid values.

      if (!hasFocus) { {
         // Validate youredittext
      }
    }
 });

注:EditTextが複数ある場合は、クラスに実装させてView.OnFocusChangeListenerから、リスナーごとにEditTextを設定し、以下のように検証することもできます。

((EditText)findViewById(R.id.edittext1)).setOnFocusChangeListener(this);
((EditText)findViewById(R.id.edittext2)).setOnFocusChangeListener(this);

    @Override
    public void onFocusChange(View v, boolean hasFocus) {

      // When focus is lost check that the text field has valid values.

      if (!hasFocus) {
        switch (view.getId()) {
           case R.id.edittext1:
                 // Validate EditText1
                 break;
           case R.id.edittext2:
                 // Validate EditText2
                 break;
        }
      }
    }

60
focusableが1つしかない場合、これは機能しませんEditText。それは焦点を失うことはありません。
Bart Friederichs

たった1つしかない場合、最良の方法は何EditTextですか?使用する必要がありますonEditorActionか?
Tux 2015年

3
が1つしかない場合EditTextは、ユーザーが画面を離れるために行うことをすべて検証します。
Christine

私はこれを試しましたが、うまくいきませんでした。Enterキーを押すたびに、次のようなメッセージが表示さW/ViewRootImpl: Cancelling event due to no window focus: MotionEvent { action=ACTION_CANCEL, actionButton=0, id[0]=0, x[0]=605.52246, y[0]=969.4336, toolType[0]=TOOL_TYPE_FINGER, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=238238, downTime=235422, deviceId=0, source=0x1002 }れます。何かを入力した場合でも、これは数字のみを受け入れるエディットテキストです。
ahitt6345 2016

1
OnFocusChangeリスナーの使用にはサイドポイントがあります。EditTextにフォーカスがあり、デバイスが回転した場合は呼び出されません。私はsomeOtherView.requestFocus()をアクティビティonPause()に置くことで解決しました。(super.onPause()の前)そうすれば、EditTextがフォーカスを失い、リスナーが呼び出されても安全です。
allofmex 2017年

60

私は個人的には、入力の終了後の自動送信を好みます。このイベントを検出する方法は次のとおりです。

宣言と初期化:

private Timer timer = new Timer();
private final long DELAY = 1000; // in ms

onCreate()などのリスナー

EditText editTextStop = (EditText) findViewById(R.id.editTextStopId);
    editTextStop.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }
        @Override
        public void onTextChanged(final CharSequence s, int start, int before,
                int count) {
            if(timer != null)
                timer.cancel();
        }
        @Override
        public void afterTextChanged(final Editable s) {
            //avoid triggering event when text is too short
            if (s.length() >= 3) {              

                timer = new Timer();
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        // TODO: do what you need here (refresh list)
                        // you will probably need to use
                        // runOnUiThread(Runnable action) for some specific
                        // actions
                        serviceConnector.getStopPoints(s.toString());
                    }

                }, DELAY);
            }
        }
    });

したがって、テキストが変更されると、タイマーは次の変更が行われるのを待ち始めます。それらが発生すると、タイマーがキャンセルされ、再度開始されます。


11
この素晴らしいですが、タイマーが使用してメモリリークを引き起こす可能性があることを注意してくださいHandler代わりに
モース麻雀

素晴らしいです、タンスク。
VipPunkJoshers Droopy 2016

serviceConnectorとは何ですか?
利他主義的な

@altruistic答えを押し出した私のコードの一部にすぎません。それはロジックが行くべき場所です。
ZimaXXX 2016年

21

これは、setOnKeyListenerまたは次のようなtextWatcherを使用して行うことができます。

テキストウォッチャーを設定する editText.addTextChangedListener(textWatcher);

次に電話します

private TextWatcher textWatcher = new TextWatcher() {

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            //after text changed
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    };

27
これは(完全な)解決策ではないようです。textWatcherは編集ごとに起動します。helloと入力すると、h、e、l、l、oに対して起動します。ユーザーがいつ「完了」したかはわかりません。 。TextWatcherがウィジェットがフォーカスを失い、ユーザーが先に移動したことを実際に知っていれば素晴らしいでしょう...
AgentKnopf

4

多くの回答は正しい方向を指していますが、質問の作成者が考えていたものに回答するものはないと思います。あるいは、私は同様の問題への回答を探していたので、少なくとも私は質問を別様に理解しました。問題は、「ユーザーがボタンを押さずに入力を停止したことを知る方法」であり、何らかのアクション(オートコンプリートなど)をトリガーします。これを行う場合は、タイマーを開始するときにユーザーが入力を停止したと見なす遅延(たとえば500〜700ミリ秒)でタイマーをonTextChangedで開始します。チェックマークを付けると何もしないことをフラグで示します)。ここに私が使用したものと同様のコードがあります:

new Timer().schedule(new TimerTask() {
  @Override
  public void run() {
     if (!running) {                            
        new DoPost().execute(s.toString());
  });
 }
}, 700);

非同期タスク内で実行中のブールフラグを変更していることに注意してください(タスクはオートコンプリートのためにサーバーからjsonを取得します)。

また、これにより多くのタイマータスクが作成されることにも注意してください(同じスレッドでスケジュールされていると思いますが、これを確認する必要があると思います)。 「ユーザーによる入力イベントの停止」がないため、タイマーを使用します


これに関する詳細情報とサンプルコードを教えていただけますか?
John Ernest Guadalupe

コードの要点は答えにあります。より詳細な例については、同じアプローチを使用するこの同じページのZimaXXXによる答えを参照してください。他にどのような情報を追加できるのかわかりません。明確でないものを指定できる場合は、詳細を追加してみます。
IgorČordaš2015年

4

アクション後にキーボードを非表示にする場合は、@ Renoと@Vinayak Bの両方が一緒に応答します

textView.setOnEditorActionListener(new EditText.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE) {
            InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(textView.getWindowToken(), 0);
            return true;
        }
        return false;
    }
});

textView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (!hasFocus) {
             // your action here
        }
    }
});

3

別のアプローチ...ここに例を示します。ユーザーが入力中に600〜1000ミリ秒の遅延がある場合、ユーザーは停止していると考えることができます。

 myEditText.addTextChangedListener(new TextWatcher() {
             
            private String s;
            private long after;
			private Thread t;
            private Runnable runnable_EditTextWatcher = new Runnable() {
                @Override
                public void run() {
                    while (true) {
                        if ((System.currentTimeMillis() - after) > 600)
                        {
                            Log.d("Debug_EditTEXT_watcher", "(System.currentTimeMillis()-after)>600 ->  " + (System.currentTimeMillis() - after) + " > " + s);
                            // Do your stuff
                            t = null;
                            break;
                        }
                    }
                }
            };
            
            @Override
            public void onTextChanged(CharSequence ss, int start, int before, int count) {
                s = ss.toString();
            }
            
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            
            @Override
            public void afterTextChanged(Editable ss) {
                after = System.currentTimeMillis();
                if (t == null)
                {
                    t = new Thread(runnable_EditTextWatcher);
                      t.start();
                }
            }
        });


2

これは確かに100%機能します。

キーボードが表示または非表示の場合、最初にリスナーをセットアップする必要があります。キーボードが表示されている場合は、おそらくユーザーが入力中です。それ以外の場合は入力済みです。

final View activityRootView = findViewById(android.R.id.content);
        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 > 100) { // if more than 100 pixels, its probably a keyboard...

                        isTyping = true;
                    } else {
//to make sure this will call only once when keyboard is hide.
                        if(isTyping){
                            isTyping = false;
                        }
                    }
            }
        });

1
複数のテキスト編集についてはどうですか?そして、heightDiff > 100ものは怖い私見です。
Bondax 14

問題ありません。問題なく動作します。このstackoverflow.com/questions/2150078/…をご覧ください
Krit

2

私はこの方法でこの問題を解決しました。コトリンを使いました。

        var timer = Timer()
        var DELAY:Long = 2000

        editText.addTextChangedListener(object : TextWatcher {

            override fun afterTextChanged(s: Editable?) {
                Log.e("TAG","timer start")
                timer = Timer()
                timer.schedule(object : TimerTask() {
                    override fun run() {
                        //do something
                    }
                }, DELAY)
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                Log.e("TAG","timer cancel ")
                timer.cancel() //Terminates this timer,discarding any currently scheduled tasks.
                timer.purge() //Removes all cancelled tasks from this timer's task queue.
            }
        })

0

私は同じ問題を抱えていて、ユーザーが[完了]または[Enter]を押すことに依存したくありませんでした。

私の最初の試みはonFocusChangeリスナーを使用することでしたが、EditTextがデフォルトでフォーカスを取得することが発生しました。ユーザーが他のビューを押すと、ユーザーがフォーカスを割り当てることなく、onFocusChangeがトリガーされました。

次の解決策は私のためにそれを行いました、そこでユーザーがEditTextに触れた場合にonFocusChangeがアタッチされます:

final myEditText = new EditText(myContext); //make final to refer in onTouch
myEditText.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            myEditText.setOnFocusChangeListener(new OnFocusChangeListener() {

                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                    if(!hasFocus){
                        // user is done editing
                    }
                }
            }
        }
}

私の場合、ユーザーが編集を完了すると画面が再レンダリングされ、myEditTextオブジェクトが更新されました。同じオブジェクトが保持されている場合は、おそらくこの投稿の冒頭で説明されているonFocusChangeの問題を防ぐために、onFocusChangeのonFocusChangeリスナーを削除する必要があります。


1秒に数回のタッチイベントが発生するたびにフォーカス変更リスナーを設定しています。こんなことしないで。
jsonfry

0

チャットアプリで「今すぐ入力」を実装しようとすると、同じ問題が発生しました。EditTextを次のように拡張してみます。

public class TypingEditText extends EditText implements TextWatcher {

private static final int TypingInterval = 2000;


public interface OnTypingChanged {
    public void onTyping(EditText view, boolean isTyping);
}
private OnTypingChanged t;
private Handler handler;
{
    handler = new Handler();
}
public TypingEditText(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    this.addTextChangedListener(this);
}

public TypingEditText(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.addTextChangedListener(this);
}

public TypingEditText(Context context) {
    super(context);
    this.addTextChangedListener(this);
}

public void setOnTypingChanged(OnTypingChanged t) {
    this.t = t;
}

@Override
public void afterTextChanged(Editable s) {
    if(t != null){
        t.onTyping(this, true);
        handler.removeCallbacks(notifier);
        handler.postDelayed(notifier, TypingInterval);
    }

}

private Runnable notifier = new Runnable() {

    @Override
    public void run() {
        if(t != null)
            t.onTyping(TypingEditText.this, false);
    }
};

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }


@Override
public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { }

}


0

私は彼女を同じ問題で終了し、onEditorActionまたはonFocusChangeでソリューションを使用できず、タイマーを試したくありませんでした。タイマーは、コードがいつ実行されるかわからないため、すべてのスレッドと予測不可能であるため、味が悪すぎる可能性があります。

onEditorActionは、ユーザーがボタンを使用せずに離れたときにキャッチしません。ボタンを使用する場合は、KeyEventがnullになる可能性があることに注意してください。フォーカスは両端で信頼できず、ユーザーはフォーカスを取得してテキストを入力したりフィールドを選択したりせずに離れることができ、ユーザーは最後のEditTextフィールドを離れる必要はありません。

私のソリューションでは、onFocusChangeと、ユーザーがテキストの編集を開始したときに設定されるフラグと、必要なときに呼び出す最後にフォーカスされたビューからテキストを取得する関数を使用しています。

すべてのテキストフィールドのフォーカスをクリアして、Leave Textビューコードをだまします。フィールドにフォーカスがある場合のみ、clearFocusコードが実行されます。onSaveInstanceStateで関数を呼び出すので、フラグ(mEditing)をEditTextビューの状態として保存したり、重要なボタンがクリックされたり、アクティビティが閉じられたりする必要がありません。

onRestoreInstanceStateコードがテキストを入力するときに反応しないようにフォーカスの条件を使用することが多いため、TexWatcherには注意してください。私

final EditText mEditTextView = (EditText) getView();

    mEditTextView.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (!mEditing && mEditTextView.hasFocus()) {
                mEditing = true;
            }
        }
    });
    mEditTextView.setOnFocusChangeListener(new View.OnFocusChangeListener() {

        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus && mEditing) {
                mEditing = false;
                ///Do the thing
            }
        }
    });
protected void saveLastOpenField(){
    for (EditText view:getFields()){
            view.clearFocus();
    }
}

0

TextView.OnEditorActionListenerタイプの代わりに使用できるこの抽象クラスのようなことをしました。

abstract class OnTextEndEditingListener : TextView.OnEditorActionListener {

    override fun onEditorAction(textView: TextView?, actionId: Int, event: KeyEvent?): Boolean {

        if(actionId == EditorInfo.IME_ACTION_SEARCH ||
                actionId == EditorInfo.IME_ACTION_DONE ||
                actionId == EditorInfo.IME_ACTION_NEXT ||
                event != null &&
                event.action == KeyEvent.ACTION_DOWN &&
                event.keyCode == KeyEvent.KEYCODE_ENTER) {

            if(event == null || !event.isShiftPressed) {
                // the user is done typing.
                return onTextEndEditing(textView, actionId, event)
            }
        }
        return false // pass on to other listeners
    }

    abstract fun onTextEndEditing(textView: TextView?, actionId: Int, event: KeyEvent?) : Boolean
}

0

EditTextでの入力完了をトリガーするのは簡単

私のために働いた、あなたがそれを変換するJavaを使用しているなら

コトリンで

youredittext.doAfterTextChanged { searchTerm ->
val currentTextLength = searchTerm?.length
    Handler().postDelayed({
        if (currentTextLength == searchTerm?.length) {
            // your code 
           Log.d("aftertextchange", "ON FINISH TRIGGER")
          }
       }, 3000)
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.