In most circumstances, I want key events to be processed by the (child) view that presently has focus, which is the default behavior, and also is what I presently have implemented.
However, under certain very specific circumstances, I would like to temporarily intercept and handle all key events (including specifically those normally handled by the child views) either in my current activity or, failing that, in my root view (it doesn't matter, so long as they are processed globally - I don't care about hardware buttons like volume +/-, as these are not handled in any of my child views anyway).
For touch events, we have onInterceptTouchEvent(), which allows a ViewGroup to watch touch events as they are dispatched to child views, and to block receipt of those events (when desired) by the child views for which they are intended.
Unfortunately, I can't find anything analogous to onInterceptTouchEvent() for key events. Am I missing something obvious, or is this an actual asymmetry in the OS?
Of course, I could just wire the current key event handler code of every child view to directly call a method on the main activity to handle the event if it wants to, and to have that activity-level method return a boolean that indicates whether it handled the event. Then, the child view could handle the event if and only if the activity method it invoked had not handled it.
But I'm hoping there's a cleaner way to simply intercept the traffic on its way "down" the hierarchy to the child view, just as onInterceptTouchEvent() does for touch events.
You can add OnGlobalFocusChangeListener
to your root view. Let's do that per activity:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(android.R.id.content).getViewTreeObserver().addOnGlobalFocusChangeListener(new ViewTreeObserver.OnGlobalFocusChangeListener() {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
if (newFocus instanceof EditText) {
((EditText) newFocus).addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
//process whatever you want
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
}
});
}
Of course if you are interested in views other than EditText
you have to figure out how to observe their changes.
As well if you want to add it globally to all of your activities use Application#registerActivityLifecycleCallbacks()
to use that code in all of your activities.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With