Get child that last had focus - android

I have found that when using a d-pad or trackball to navigate in my app if you move to the right and the list view looses focus, when the list view regains focus, a different child is given focus than last had focus. I tried to use onFocusChange(...) to save which child had focus but it looks like this isn't called until after the focus is lost so I can never grab which child last had focus. Is there a way to grab who had focus so I can then call requestFocus() on the child once the list view grabs focus again?
Unfortunately I cannot use a handler because this isn't a much used feature and I don't want to sacrifice the performance for a smaller feature.
Here is the code I had that didn't work (focusedView was always null no matter what):
mainListView.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if(focusedView == null ) { Log.i("focus", "focusedView == null"); }
if(hasFocus && focusedView != null) {
Log.i("focus", "Focus has been Recieved.............");
focusedView.requestFocus();
} else {
// Focus has been lost so save the id of what the user had selected
Log.i("focus", "Focus has been Lost.............");
focusedView = mainListView.findFocus();
}
}
});
Thanks!

I think you are spot on with your own answer, bascially since the focus listener is called after its lost focus, no child will be in focus and therefore .findFocus() will return null.
I recon you best bet is to extend the ListView class, and override the onFocusChanged method. Basically do what you are doing, but do it inthere when gainFocus is true.
#Override
protected void onFocusChanged (boolean gainFocus,
int direction, Rect previouslyFocusedRect) {
if(gainFocus)
focusedView = mainListView.findFocus();
}
This one

Related

Loop focus in RecylerView for Tv

according to https://developer.android.com/training/tv/start/navigation
You should set up the navigation order as a loop, so that the last
control directs focus back to the first one.
I have tried to implement such behavior for RecyclerView items:
fun RecyclerView.loopFocusVertically() {
viewTreeObserver.addOnGlobalLayoutListener {
val children = getAllChildren()
val firstFocusableItem = children.firstOrNull { it.isFocusable }
val lastFocusableItem = children.lastOrNull { it.isFocusable }
firstFocusableItem?.let { it.nextFocusUpId = lastFocusableItem?.id ?: it.id }
lastFocusableItem?.let { it.nextFocusDownId = firstFocusableItem?.id ?: it.id }
}
}
So on layout change i made first view have nextFocusUpId reference to last view, and the last view nextFocusDownId reference to first view. But it only works in case all views are actually layouted on screen, which obviously is not true in general case. RecyclerView actually recycles views, so last and first view may not exist at the same time on screen
How to implement focus loop for rv in leanback mode?
I have tried to use androidx.leanback.widget.VerticalGridView from leanback library, but it also doesn't have required behavior.
By default on pressing up from first focusable item of rv focus jumps to some other focusable view outside of rv, which is not so appropriate
By default on pressing up from first focusable item of rv focus jumps to some other focusable view outside of rv, which is not so appropriate
First, as for the UX, it's really problematic if you have views above your list so pressing up will really be an issue if to scroll to the last item as you want or to go to the above view.
With that said I'd suggest you give the loop option only from bottom in this case if you have a view above the list that should also get focus.
In general, I suggest you check VerticalGridView/HorizontalGridView for adding rows and lists in a lean-back app.
In the example I adjusted it to use a RecyclerView for your question.
For doing so you'll have to catch the button event, check if its the last item and if so, request focus to the first item.
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_UP) {
if (event.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
if (onDownClick(event)) {
return true;
}
}
}
return super.dispatchKeyEvent(ev);
}
public boolean onDownClick(KeyEvent event) {
int currentIndex = 0;
if (mAdapter != null) {
currentIndex = mAdapter.indexOf(mCurrentItem);
}
if (currentIndex == mAdapter.size() - 1) {
mListRecycler.scrollToPosition(0);
if (mListRecycler.findViewHolderForAdapterPosition(0) != null) {
mListRecycler.findViewHolderForAdapterPosition(0).itemView.requestFocus();
}
return true;
}
return false;
}

Is possible in android to know which view gains focus from the current view that looses it?

I have an activity with 2 types of views EditText and CustomEditText my custom edit text has a onFocusChanged()method and I can know when the view gains and looses focus, but I would like to know which view gains focus in order to perform different actions, is possible to know from the onFocusChanged() method which view got focus after this view looses it?
Calling getCurrentFocus() from the overwritten method in a custom view like this will return null so that will not work
#Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (focused ) {
}else{
Activity activity = (Activity) this.getContext();
activity.getCurrentFocus();//this returns null
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}

How to pass the focus state to View's parent?

How can a view detect its child view's focus state? As you can see in this picture.
The parent view is a LinearLayout with a child view EditText. I wanna change the UI while the focus state changed(linearlayout turns red if focus on the edittext). But only the EditText can detect the focus state while the LinearLayout can not. Of cause I can listen the EditText's state using OnFocusChangedListrner. But I don't satisfy with it. Is there a simple way to make the parent view get the child view's focus event? The form has a lot of items.
I also think there is no other method than
onfocusChangeListner
If you have many edittext then you simply make one method with the parameter and inside it you write only one onfocuschangeListner like this
public void setColorToEditText(EditText editText) {
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
Log.e("userFocu", "userFocu");
if (!hasFocus) {
// code to execute when EditText loses focus
}
}
});

How to check if a particular view is currently focussed in Android

In my android app
I need to check whether a particular view is focussed.
Now I found the getCurrentFocus() function in Activity class
but this returns a View Object.
How can I compare and check whether this returned View is same as the one in question.
I mean there is no getName() function here.
So after getting the View object, how can I compare to check which View class is this ?
The View.isFocused() method tells whether the view in question is focused or not.
if (myView.isFocused()) {
// your code
}
If you still want to use the getCurrentFocus() method, you can simply check:
View focusView = getCurrentFocus();
if (myView == focusView) {
// your code
}
Or else, you can compare your views by id.
View focusView = getCurrentFocus();
if (focusView != null && myView.getId() == focusView.getId()) {
// your code
}
You could use the getId() method I guess?
e.g.
getCurrentFocus() == R.id.myView;
getCurrentFocus() on the parent view
http://developer.android.com/reference/android/app/Activity.html#getCurrentFocus%28%29
No need for getName(). Just use the == operator. See:
View myView = findViewById(...);
if (activitygetCurrentFocus() == myView)
// ha focus
}
Another option, one I usually prefer, is to set a focus listener for the views you are interested in monitoring:
myView.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
// got focus logic
}
}
});

Android: When the on-screen keyboard appears and disappears, are there any listeners that are automatically called?

I was wondering if there is any way to be notified automatically by android when the on-screen keyboard is shown and when it disappears.
For example when we click on a edittext, the ime appears. Will there be any event calls?
And when it disappears when we press back, similarly will there be any even calls?
I found this thread Android: which event fires when on screen keyboard appears? , however no answers have been reached yet.
The purpose is because i need an event to automatically manipulate visibility. I have an activity with an edittext on the top of the screen, below it, a listview and a linearlayout which are sitting on top of each other. To control what the user sees, i manipulate the visibility. By default, the linearlayout is shown initially, however, when the user is entering text, the listview should be shown instead. The listview should disappear when the user has finished typing, which in this case, the on-screen-keyboard will be closed.
I tried acomplishing the change of visibility using onFocusChange, however, even when the on-screen keyboard disappears, the edittext still retains focus and the linearlayout never reappears.
Below is my implementation of the onFocusChange
#Override
public void onFocusChange(View v, boolean hasFocus)
{
if(v.getId()==R.id.search_screen_keyword_textbox)
{
if(hasFocus)
{
filterSection.setVisibility(View.GONE);
autoComSection.setVisibility(View.VISIBLE);
}
else
{
filterSection.setVisibility(View.VISIBLE);
autoComSection.setVisibility(View.GONE);
}
}
else if(v.getId()==R.id.search_screen_location_textbox)
{
if(hasFocus)
{
filterSection.setVisibility(View.GONE);
autoComSection.setVisibility(View.VISIBLE);
}
else
{
filterSection.setVisibility(View.VISIBLE);
autoComSection.setVisibility(View.GONE);
}
}
else
{
filterSection.setVisibility(View.VISIBLE);
autoComSection.setVisibility(View.GONE);
}
}
If anyone has any idea about it do let me know. :D
You can catch the back button when in an edittext, this is what would make the keyboard disappear. Using this method:
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
// Do your thing here
return false;
}
return super.dispatchKeyEvent(event);
}
Search is great: onKeyPreIme or Android API
It seems that this thread has a solution using onConfigurationChanged: How to capture the "virtual keyboard show/hide" event in Android?

Categories

Resources