Android RecyclerView Edittext issue - android

I'm creating a list of editable items (received from backend). I'm using the "new" recyclerview for this. There a couple of possible viewTypes in my recyclerview:
checkbox
spinner
edittext
The problem I'm having is with the EditText gaining focus. AdjustResize kicks in fine and my keyboard is shown. But the EditText that has gained focus isn't visible anymore in the list. (position in the list in the now resized portion is below the visible positions). I don't want to be using AdjustPan in this case because on top there is a pager & stuff I would like to keep fixed there..

This is happening because, at the time the keyboard is shown, your EditText does not exist anymore. I have made several attempts to find a clean solution to this problem maintaining adjustResize input mode and good user experience. Here's what I ended up with:
To ensure that EditText is visible before the keyboard is shown, you will have to scroll the RecyclerView manually and then focus your EditText.
You can do so by overriding focus and click handling in your code.
Firstly, disable focus on the EditText by setting android:focusableInTouchMode property to false:
<EditText
android:id="#+id/et_review"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusableInTouchMode="false"/>
Then you have to set a click listener for the EditText where you will manually scroll the RecyclerView and then show the keyboard. You will have to know the position of your ViewHolder which contains the EditText:
editText.setOnClickListener(new View.OnClickListener() {
#Override public void onClick(View v) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
// you may want to play with the offset parameter
layoutManager.scrollToPositionWithOffset(position, 0);
editText.setFocusableInTouchMode(true);
editText.post(() -> {
editText.requestFocus();
UiUtils.showKeyboard(editText);
});
}
});
And finally, you must make sure that the EditText is made not focusable again when it naturally looses focus:
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
editText.setFocusableInTouchMode(false);
UiUtils.hideKeyboard();
}
}
});
This is far from a simple and clean solution, but hope it will help the way it helped me.

I've had the same issue. Long story short - there is no right and elegant solution. Focus handling was always a big pain in Android.
There multiple reasons why you are loosing focus:
Keyboard hides the descendant EditText views
Next EditText is not rendered, because RecycleView hasn't even created a ViewHolder for it. Example: you have 10 views, and 5 of them are on screen and others aren't visible, because those are below.
Some other view consumes focus, in example CheckBox or some DatePicker
RecyclerView due to scroll events consumes focus
Bunch of other hidden under-the-hood stuff
Few words in terms of architecture and structural approach in my solution:
Everything works with Data binding
RecyclerView works with Adapter that supports AdapterDelegate approach
Each EditText, Spinner, DatePicker, CheckBox or RadioButton group is a separate ViewModel which is a separate unit and handles a lot of stuff on its own.
I've used a lot of tricks and mixed them together. As someone already mentioned, the first step would be to add those params to your RecyclerView:
android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true"
Base view model for all possible inputs has defined interface, let's call it SingleInputViewModel, among that interface you can have defined next functions/methods:
void onFocusGained();
void onFocusLost();
boolean isFocusable();
In each particular input item implementation you are able to control focus, for example you are able to implement CheckBox as non-focusable and focus will jump to next isFocusable() == true item. Also you will be able to control the state and action depending on consuming/gaining focus on particular view.
Next step for fixing some of the focus passing issues - was scrolling RecyclerView when IME_ACTION_NEXT occurs. In such case you need to delegate your scroll logic to LayoutManager.scrollHorizontallyBy() or LayoutManager.scrollToPosition() with calculating appropriate offset or position.
Hard and elegant approach is to override logic inside LayoutManager, which is also responsible for focus handling. LinearLayoutManager has a lot of hidden logic, which you won't be able to override, so probably you will need to write a lot of code from scratch.
And the last and the most complex way to fix that is to extend RecyclerView and override focus search related funs/methods:
RecyclerView.focusSearch()
RecyclerView.isPreferredNextFocus()
RecyclerView.onRequestFocusInDescendants()
RecyclerView.onFocusSearchFailed()
RecyclerView.onInterceptFocusSearch()
RecyclerView.onRequestChildFocus()
P.S. Have a look at the FocusFinder and it's usage, just for general knowledge. Now you have few option to choose. I hope you will find something helpful. Good luck!

Using this in layout worked :
android:descendantFocusability="beforeDescendants"
<android.support.v7.widget.RecyclerView
android:id="#+id/recyclerview"
android:descendantFocusability="beforeDescendants"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="#+id/extrasLayout"
android:layout_below="#+id/anchorView"
android:layout_marginTop="#dimen/margin5"
android:fastScrollEnabled="false"
/>
Manifest file : Add this to the activity section android:windowSoftInputMode="stateHidden|adjustPan"
<activity
android:name=".activites.CartActivity"
android:label="#string/title_activity_cart"
android:exported="true"
android:windowSoftInputMode="stateHidden|adjustPan"
android:parentActivityName=".activites.HomeActivity"
android:screenOrientation="portrait">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activites.HomeActivity"/>
</activity>

Ok
I found a solution for this problem
I'm using a library for that and it solved easily.
when you make your recyclerView by this template, it solves this problem automatically.
NOTE: for checkbox and radiobutton only
use this
https://github.com/TakeoffAndroid/RecyclerViewTemplate

I'm going to post my solution because after 2 days being blocked by this I hope that it could help someone else.
My issue was that the RecyclerView was a wrap_content on the height, meaning it didn't have a fixed height, and every time i clicked for the first time on one of the edit text inside it, it wasn't giving the focus on the first tap, but it was just showing the keyboard, on the second tap it was gaining the focus.
The fix was to make sure the RecyclerView has a fixed height or match_parent, i don't really know why but this worked for me!
Hope it helps

I put all these three things in recyclerview finally it stopped recyclerview edittext gaining focus
android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true"

This is happening because from the android 9.0 you have to write post()-> to gain focus of edittext in Previous versions you can just put
edittext.requestFocus();
but from 9.0 you have to run thread to gain focus of edittext like this
et.post(() -> {et.requestFocus();});

You can scroll recyclerview to selected recycler item position on edit text focus change listener . Have a look at link to use scroll option How to use RecyclerView.scrollToPosition() to move the position to the top of current view?

Related

Android EditText in RecyclerView

I want to implement a search. But unfortunately edit text must be in recycler view. I have multiple types of items.
When user enters a letter I refresh whole adapter, searching is done locally. That means that keyboard disappears and edit text is losing focus, because of this constant updating.
I managed to fix it showing keyboard and focus an edit manually while binding.
if (item.inEditableMode) {
edit_text.requestFocus()
showKeyboard(edit_text)
}
But edit text works not that good as I expect. A problem can be seen when user types fast or wants to clear input.
Thanks for help.
Layout:
"unfortunately edit text must be in recycler view" - I bet it do NOT have to be a part of RecyclerView not part of Adapter list item View. better inspect your layout architecture instead of posted workarounds with hiding-showing (blinking) keyboard
besides that even when it must be then don't notify whole Adapter with notifyDataSetChanged(), instead use notifyItemChanged(...) - notify range of of your items, but not list item with EditText - it won't be redrawn, so keyboard should stay visible and focus kept on that field. still this isn't good approach, your EditText should be separated from RecyclerView almost for shure

ExitText on recycler-view cause problem in focus and fixing it breaks the keyboard hiding EditTect visibility

Had a problem from recycler view and EditText. The focus is lost because of the view refresh. Have fixed this with below config from manifest.
android:windowSoftInputMode="stateHidden|adjustResize|adjustPan"
However, this breaks my existing functionality. The EditText hidden behind the keyboard. To solve this the config needs to be changed.
android:windowSoftInputMode="adjustResize"
How can I solve both problems with a single config.
After a long hurdle, the workaround was found but not sure whether it is a good one.
From the recycler Adapter:
Added focus change listener to the edit-text from onBindViewHolder
When the focus gained, the index been captured to variable from adapter
Check the last focus index (Step 2) in onBindViewHolder if it is equal to current index then make request focus to current input.
Tested from various builds and it worked fine.

EditText inside list view android loses focus and data getting copied into another records

I am working on a custom listView which contains editText in every list item.
My listItem is in fragment, and its activity has already adjustResize property which i can not change to adjustPan. Problem is when I click the edittext it is losing focus and even after two three clicks if it gains focus , then upon scrolling that value gets copied into another records and keyboard gets hanged.
I am using
android:descendantFocusability="beforeDescendants"
on my listView. Also i am using ViewHolder pattern in my adapter . Any tested links or working piece of code is really appreciated.
I had a similar issue dealing with RecyclerView with EditText's in the rows recently so this might help you.
When the keyboard comes up your list resizes and maybe the row that caused the keyboard to come up is not visible any more. You need to scroll to it and give it focus back.
How would you know that the keyboard is up? There is no elegant way, I do it by setting GlobalLayoutListener on the recyclerView, saving it's original size, and listening for a smaller size being reported. Search for "android keyboard listener" and you'll find some code.
When user taps on a EditText save the position of the row.
Listen for global layout changes to figure out that the keyboard is up.
Scroll to the row with the saved position.
Give the EditText focus. (probably in a posted Runnable to wait for the scroll to actually happen)

EditText in Listview loses focus when pressed on Android 4.x

I know there are a lot of similar questions out here
but I couldn't get any of the provided solutions working in a simple sample app.
The problem occurs when the softkeyboard is shown for the first time. As soon as it is shown, only by pressing the editText again makes it editable.
Tried the following:
android:windowSoftInputMode="adjustPan|adjustResize"
This is not solving any issues. It seems that this line is mandatory to have the activity resized after the softkeyboard is popping up. Unfortunately, it's also causing any EditTexts to lose focus. This is probably to the ListView itself gaining focus after the resizing process. So I tried the following workaround:
listView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
This always causes the first visible EditText that the ListView contains to gain focus, which is undesirable. The second EditText in the second row should instead gain focus when pressed, which is not happening. Also, if I eventually managed to focus another EditText other then the first one shown (e.g. by pressing 'Next' on the softkeyboard), the first visible one will receive focus after the keyboard is dismissed and the ListView being resized to its full size again.
I tried several other things like intercepting onFocusChange() events for the ListView, while knowing which EditText was pressed by its TouchListener. Requesting the focus for that certain EditText again did not lead to any success either.
Using a ScrollView instead of a ListView as suggested by other users is not an option either for the concerned project.
A classic hack for situations like this is to use a handler and postDelayed(). In your adapter:
private int lastFocussedPosition = -1;
private Handler handler = new Handler();
public View getView(final int position, View convertView, ViewGroup parent) {
// ...
edittext.setOnFocusChangeListener(new OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
if (lastFocussedPosition == -1 || lastFocussedPosition == position) {
lastFocussedPosition = position;
edittext.requestFocus();
}
}
}, 200);
} else {
lastFocussedPosition = -1;
}
}
});
return convertView;
}
This works on my device, but keep this code out of production. I also wouldn't be surprised if the focus bug manifests itself differently in different android versions or roms.
There are also many other problems with embedding an EditText within a ListView that have solutions that feel like a hack. See all of the other people struggling.
It's also very easy to have something like this happen:
.
After having gone down similar paths many times myself, I've mostly given up on trying to override any of the default keyboard behaviours or quirks. I would recommend trying to find alternative solution in your app if possible.
Have you considered having the ListView rows be just a styled TextView and then displaying a Dialog with an EditText when a row is clicked, updating the TextView as necessary?
I was having problems with the ActionBar "stealing" focus when I pressed on an EditText located within a ListView row. The above solutions did not work, but the following solution worked for me:
http://www.mysamplecode.com/2013/02/android-edittext-listview-loses-focus.html
Basically I added this to my ListView:
android:descendantFocusability="beforeDescendants"
and added this to my activity:
android:windowSoftInputMode="adjustPan"
Modify your manifest xml to add windowSoftInputMode in your activity:
<activity
android:name=".YourActivity"
android:windowSoftInputMode="adjustPan">
</activity>
I know its a very old thread but this answer might be helpful to someone so here it is:
Switch to RecyclerView and you won't have to worry about these annoying issues of ListView. Instead of making new view it recycles and reuses old views.
I was having the same problem with recyclerView and trying all suggested solutions.
Finally, the problem on my case was that the recyclerView had wrap_content as value for the height on my XML by accident; changed it to match_parent and started working as expected, no focusable value set and using android:windowSoftInputMode="adjustResize"
Use Recycler View, this solves several issues from list and gridview. You can even work with staggered gridviews. You could easily start working with this.
When the list is long enough to cover the soft keyboard, the
EditText in Listview loses focus when pressed on Android 4.x.
One solution is to wrap the Listview in a linear layout with a height of half the screen.
Whenever the Listview doesn't cover the softkeyboard, everything is fine.
was having the same issue. Searched for all such solutions with inputMode, focusability et al. Best solution, migrate to recycler view.
In my case I've added local value currentlyFocusedRow in my Adapter.
In the method getView() I've add these code to each editText:
if (currentlyFocusedRow == position) {
editText.requestFocus();
}
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
if (currentlyFocusedRow == -1) {
currentlyFocusedRow = position;
}
} else {
currentlyFocusedRow = -1;
}
}
});

Android list - edittext in header of list

I have a List in Monodroid which has a header with an EditText. The problem is that EditText not getting focus properly. Here is how it works:
If you touch the EditText, the keyboard comes up correctly, but if you press any key, nothing happens.
Hide the keyboard with the back button
If you touch the EditText again it works correctly
I tried to debug it and first time FocusChange event fires twice, first with the HasFocus = true, and second time with HasFocus = false.
Any suggestions what am I doing wrong?
UPDATE
Here is what solved my problem:
I set this to my ListView in XML:
android:descendantFocusability="afterDescendants"
And to my ListView in code:
ListView.ItemsCanFocus = true;
And this to my EditText:
android:focusableInTouchMode="true"
android:focusable="true"
And Voilá it works like a charm. Thank you Bradley!
I would suggest putting the EditText above your ListView in the layout xml instead of adding it to the header.
I have ran into this situation before and could never get 100% reliability out of a single solution. If a brute force approach is the only solution, try different combinations of the following properties on the ListView object: DescendantFocusability, ItemsCanFocus, Focusable.

Categories

Resources