Erkennen, wann der Benutzer die Softtastatur geschlossen hat

114

Ich habe ein EditText-Widget in meiner Ansicht. Wenn der Benutzer das EditText-Widget auswählt, werden einige Anweisungen angezeigt und die Softtastatur wird angezeigt.

Ich verwende einen OnEditorActionListener, um zu erkennen, wann der Benutzer die Texteingabe abgeschlossen hat, und ich entlasse die Tastatur, verstecke die Anweisungen und führe eine Aktion aus.

Mein Problem ist, wenn der Benutzer die Tastatur durch Drücken der Taste ZURÜCK schließt. Das Betriebssystem schließt die Tastatur, aber meine Anweisungen (die ich ausblenden muss) sind immer noch sichtbar.

Ich habe versucht, OnKeyDown zu überschreiben, aber das scheint nicht aufgerufen zu werden, wenn die Taste BACK zum Schließen der Tastatur verwendet wird.

Ich habe versucht, einen OnKeyListener im EditText-Widget festzulegen, aber das scheint auch nicht aufgerufen zu werden.

Wie kann ich erkennen, wann die Softtastatur geschlossen wird?

deSelby
quelle

Antworten:

160

Ich kenne einen Weg, dies zu tun. Unterklasse den EditText und implementiere:

@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
  if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
    // Do your thing.
    return true;  // So it is not propagated.
  }
  return super.dispatchKeyEvent(event);
}

Hier ist ein Link zur Verwendung Ihrer benutzerdefinierten Ansichten (für die Unterklasse EditText): http://developer.android.com/guide/topics/ui/custom-components.html

Jay
quelle
2
Ich erhalte Berichte von Android-Benutzern mit Hardwaretastaturen, dass dies das Drücken von Tasten irgendwie stört. Ich habe derzeit keine zusätzlichen Informationen.
Silber
Ich habe nach mehreren Lösungen gesucht, dies ist bei weitem die beste!
Friesgaard
10
Warte, warte, warte, ich habe mir das nur ein drittes Mal angesehen - sollte der Superanruf nicht sein onKeyPreIme? Oder gibt es einen bestimmten Grund dafür, dass es nicht so ist?
Erhannis
Sieht nützlich aus, außer wenn der EditText nicht in Unterklassen unterteilt werden kann (z. B. in einer Suchansicht). Dies ist ein Problem, wenn Sie versuchen, die Suchansicht auszublenden, wenn sie leer ist, wenn die Tastatur geschlossen wird. Ich muss mich fragen, warum die Android-Leute nicht einfach ein paar nette OSK-APIs für solche Dinge bereitstellen.
TBB
2
@tbm Um einen ähnlichen Effekt in zu erzielen SearchView, lesen
Cheok Yan Cheng
124

Jay, deine Lösung ist gut! Vielen Dank :)

public class EditTextBackEvent extends EditText {

    private EditTextImeBackListener mOnImeBack;

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

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

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

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && 
            event.getAction() == KeyEvent.ACTION_UP) {
            if (mOnImeBack != null) 
                mOnImeBack.onImeBack(this, this.getText().toString());
        }
        return super.dispatchKeyEvent(event);
    }

    public void setOnEditTextImeBackListener(EditTextImeBackListener listener) {
        mOnImeBack = listener;
    }

}

public interface EditTextImeBackListener {
    public abstract void onImeBack(EditTextBackEvent ctrl, String text);
}
olivier_sdg
quelle
Gibt es einen bestimmten Grund, den wir ebenfalls erkennen möchten KeyEvent.ACTION_UP?
Cheok Yan Cheng
2
@CheokYanCheng Dies liegt daran, dass Benutzeraktionen normalerweise beim Loslassen der Taste wirksam werden sollten und nicht beim Drücken.
Jayeffkay
3
Stellen Sie sicher, dass Sie android.support.v7.widget.AppCompatEditTextzum Abtönen verlängern.
Sanvywell
Verlängern: AppCompatEditTextfür AndroidX
COYG
Toll! Ich würde nur eine Verbesserung vorschlagen, um Ihre Lösung zu generieren. Ich würde die Argumente von onKeyPreIme "wie sie sind" an den Listener weitergeben. Auf diese Weise können Sie Ihre Logik auf verschiedene Arten implementieren, wo Sie sie benötigen.
marcRDZ
17

Ich habe Jays Lösung leicht geändert, indem ich super.onKeyPreIme () aufgerufen habe:

_e = new EditText(inflater.getContext()) {
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK){
            cancelTextInput();
        }
        return super.onKeyPreIme(keyCode, event);
    }
};

Wunderbare Lösung, Jay, +1!

Steelight
quelle
14

Hier ist mein benutzerdefinierter EditText, um festzustellen, ob die Tastatur angezeigt wird oder nicht

/**
 * Created by TheFinestArtist on 9/24/15.
 */
public class KeyboardEditText extends EditText {

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

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

    public KeyboardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        if (listener != null)
            listener.onStateChanged(this, true);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
                && event.getAction() == KeyEvent.ACTION_UP) {
            if (listener != null)
                listener.onStateChanged(this, false);
        }
        return super.onKeyPreIme(keyCode, event);
    }

    /**
     * Keyboard Listener
     */
    KeyboardListener listener;

    public void setOnKeyboardListener(KeyboardListener listener) {
        this.listener = listener;
    }

    public interface KeyboardListener {
        void onStateChanged(KeyboardEditText keyboardEditText, boolean showing);
    }
}
Der beste Künstler
quelle
8

Es ist jetzt 2019 ...
Also habe ich mit Kotlin eine ordentlichere Lösung geschaffen

1.Erstellen Sie eine Erweiterungsfunktion:

fun Activity.addKeyboardToggleListener(onKeyboardToggleAction: (shown: Boolean) -> Unit): KeyboardToggleListener? {
    val root = findViewById<View>(android.R.id.content)
    val listener = KeyboardToggleListener(root, onKeyboardToggleAction)
    return root?.viewTreeObserver?.run {
        addOnGlobalLayoutListener(listener)
        listener
    }
}

2.Wo sich der Toggle-Listener befindet:

open class KeyboardToggleListener(
        private val root: View?,
        private val onKeyboardToggleAction: (shown: Boolean) -> Unit
) : ViewTreeObserver.OnGlobalLayoutListener {
    private var shown = false
    override fun onGlobalLayout() {
        root?.run {
            val heightDiff = rootView.height - height
            val keyboardShown = heightDiff > dpToPx(200f)
            if (shown != keyboardShown) {
                onKeyboardToggleAction.invoke(keyboardShown)
                shown = keyboardShown
            }
        }
    }
}

fun View.dpToPx(dp: Float) = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).roundToInt()

3. Verwenden Sie es in einer so einfachen Aktivität :

addKeyboardToggleListener {shown ->
          // hurray! Now you know when the keyboard is shown and hidden!!
      }
Leo Droidcoder
quelle
Danke für die Kotlin-Lösung. Als ich es implementierte, bemerkte ich, dass es den Listener mehrmals für einen Tastaturwechsel und auch beim Start auslöst. Ich musste den Status open / not open speichern und Listener nur aufrufen, wenn der Wert tatsächlich anders war.
RandomEngy
@RandomEngy hat es in KeyboardToggleListener behoben. Vielen Dank für
Ihre Nachricht
4

Erstellen Sie einfach eine Klasse, die Edittext erweitert, und verwenden Sie diesen Edittext in Ihrem Code. Sie sollten lediglich die folgende Methode im benutzerdefinierten Edittext überschreiben:

@Override
 public boolean onKeyPreIme(int keyCode, KeyEvent event) {
 if (keyCode == KeyEvent.KEYCODE_BACK) {

    //Here it catch all back keys
    //Now you can do what you want.

} else if (keyCode == KeyEvent.KEYCODE_MENU) {
    // Eat the event
    return true;
}
return false;}
farhad.kargaran
quelle
Gibt es eine Möglichkeit zu erkennen, wann die Tastatur geöffnet wird?
Pulver366
3

Hier ist eine Lösung mit dem Key Listener. Ich habe keine Ahnung, warum dies funktioniert, aber OnKeyListener funktioniert, wenn Sie onKeyPreIme in Ihrem benutzerdefinierten EditText nur überschreiben.

SomeClass.java

customEditText.setOnKeyListener((v, keyCode, event) -> {
            if(event.getAction() == KeyEvent.ACTION_DOWN) {
                switch (keyCode) {
                    case KeyEvent.KEYCODE_BACK:
                        getPresenter().onBackPressed();
                        break;
                }
            }
            return false;
        }); 

CustomEditText.java

@Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        return super.dispatchKeyEvent(event);
    }
Rubin Yoo
quelle
3

Mit der Antwort von @ olivier_sdg, aber konvertiert nach Kotlin:

class KeyboardEditText : AppCompatEditText {

    var listener: Listener? = null
  
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
  
    override fun onKeyPreIme(keyCode: Int, event: KeyEvent): Boolean {
        if (event.keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
            listener?.onImeBack(this)
        }
        return super.dispatchKeyEvent(event)
    }
  
    interface Listener {
        fun onImeBack(editText: KeyboardEditText)
    }

}

Verwendung:

keyboardEditText.listener = object : KeyboardEditText.Listener {
    override fun onImeBack(editText: KeyboardEditText) {
        //Back detected
    }
}
bmjohns
quelle
2

Für alle, die dasselbe in Xamarin tun möchten, habe ich einige der wichtigsten Antworten übersetzt, da es etwas anders ist. Ich habe hier einen Kern erstellt , aber zusammenfassend erstellen Sie einen benutzerdefinierten EditText und überschreiben ihn OnKeyPreImewie folgt :

public class CustomEditText : EditText
{
    public event EventHandler BackPressed;

    // ...

    public override bool OnKeyPreIme([GeneratedEnum] Keycode keyCode, KeyEvent e)
    {
        if (e.KeyCode == Keycode.Back && e.Action == KeyEventActions.Up)
        {
            BackPressed?.Invoke(this, new EventArgs());
        }

        return base.OnKeyPreIme(keyCode, e);
    }
}

... und dann in der Ansicht ...

editText = FindViewById<CustomEditText>(Resource.Id.MyEditText);
editText.BackPressed += (s, e) => 
{
    // <insert code here>
};
Steven Evers
quelle
Obwohl dies nur ein einfaches Beispiel ist, würde ich empfehlen, keine anonymen Methoden in Ereignishandlern zu verwenden, da diese Speicherlecks verursachen und viele Leute die hier gefundenen Beispiele verwenden und mit ihnen ausführen, ohne dies zu bemerken. Quelle: docs.microsoft.com/en-us/xamarin/cross-platform/deploy-test/…
Jared
0

hideSoftInputFromWindow Gibt true zurück, wenn die Tastatur geschlossen wird. Verwenden Sie den Wert, um das Schließen der Tastatur in Android zu erkennen

InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);

        if (imm.hideSoftInputFromWindow(findFocus().getWindowToken(),
                InputMethodManager.HIDE_NOT_ALWAYS)) {
            //keyboard is closed now do what you need here
        }
Bali
quelle