I have a ListView with custom rows. When any of these rows is
clicked, the ListView's data is regenerated. I'd like the list to
scroll back to the top when this happens.
I initially tried using setSelection(0) in each row's OnClickListener
to achieve this but was unsuccessful (I believe because the ListView
loses its scroll position when its data is invalidated - so my call to
setSelection is undone. I still don't understand how the ListView
decides where to scroll to after invalidation, though).
The only working solution I know of was given by Romain Guy here:
http://groups.google.com/group/android-developers/browse_thread/thread/127ca57414035301
It involves (View.post)ing the call to _listView.setSelection(0). I
found this to perform quite poorly.
The newly generated list shows up with its scroll location unchanged
and there is a considerable delay before it scrolls back to the top.
Is there any better way to achieve this functionality?
Any help would be much appreciated.
Thanks!
call listView.setSelectionAfterHeaderView(); to scroll to top
I have tried lot but this one worked for me
list.smoothScrollToPosition(0);
I simply use listview.setSelection(0);
Works fine for me.
If you need instant scroll just after ListView adapter's data was changed, pay attention that it might not be yet populated. In this case you should post() your setSelection() or setSelectionAfterHeaderView() via Handler so it will be called later in the queue.
listView.Handler.post(new Runnable() {
#Override
public void run() {
listView.setSelectionAfterHeaderView();
}
});
This worked for me.
Personally, I recommend you find a different UI pattern. It is possible that users will find your current "click, and the list changes in situ" approach intuitive, but I am skeptical.
You could try subclassing ListView and overriding layoutChildren() to chain to the superclass, then call setSelection(0) in the case where that is needed. If the "considerable delay" is due to just the post() call, this should clear it up.
as a workaround, you can create a new adapter containing the new regenerated data, then call ListView.setAdapter. after that call ListView.setSelection(n).
btw, the solution provided by commonsware is worked.
On some different requirement.
If you want to scroll up just like while chatting.
mListView.smoothScrollToPosition(mAdapter.getCount());
This one worked fine when you want to focus the edittext from listview header
listview.setSelectionFromTop(0,0);
If you want to select the particular index view from listview then
listview.setSelection(index); // o for top
Related
I tried with empty onBindViewHolder still the same issue
If you can help please drop your answer i would really appreciate that
yes, this issue occurs just because it's recyclerview's default behavior.
recyclerview doesn't create a new cell for every view it only creates a view of visible items at a time and then replaces this cell with a previous one while you scroll down.
so you need to maintain their state manually to handle this situation. click here for more references.
I think I've read all the answers to all of the similar questions, and none of them seem to be fixing my problem,they're only workaround. I have recycler view with pictures taken by camera and they only update on scroll.
Using a smoothScrollToPosition() is workaround and I want to know the cause of this issue and fix it.
It's really weird because when a open my fragment and have a couple of images in the recycler view which I added earlier, deleting elements works perfect, but when I add new image from camera intent even the notification for deleting stops working, I have to do a scroll to refresh items in the adapter.
This is the part where I set the data:
viewModel.photos.observe(viewLifecycleOwner, Observer {
list->adapter.data = list
}).
Of course data is set in OnUiThread :
I checked with the debugger-- elements in list are updated.
Does anyone know the cause of this issue?
You have to tell recyclerView.adapter what exactly changed by calling notifyItemChanged. There are also other methods for inserted items, moved items, deleted items, etc. You can look at the full documentation here:
There is also another way by implementing a DiffUtil. You can research about it more. But the difference is that by using DiffUtil, you won't have to manually call those notify methods yourself.
Also, the old/unoptimized/unrecomenended way to do this is to simply call notifyDataSetChanged().
P.S. I highly think you found the somewhat the same answer while searching online and might have thought it as simply "a work around". I'm here to tell you that this is how its supposed to be handled.
I have a RecyclerView with setStackFromEnd(true) representing a chat list. And I want to load older messages when the list is scrolled to the top. I managed to do this using onScrollListener.
But when I add items to the adapter with messages.addAll(0, aListWithNewMessages) (messages is data set for adapter) and call notifyDataSetChanged(), new list items (as expected) appear before the existing ones and shift them down (not the experience a user wants), and I want to add them silently so a user shouldn't see it.
So my guess for how to tackle this issue is to scroll list to somehow previously saved position.
I understand that this is not a bug or an unexpected behavior, so please help to sort it out.
Thanks
Try being more specific. Instead of calling notifyDataSetChanged() use notifyItemRangeInserted or similar RecyclerView methods. That will allow RecyclerView to know what to do and will provide much better UX.
My problem is on two fronts.
First issue: Scrolling amnesia
I have a ListView with spinners and edit texts. It acquires it's data from webservice. The problem is when I write up a value on the EditText or select something for the spinners and scroll them out of view. When I come back the fields are empty and the spinners are again in their default selection.
Attempted solution
I have tried resolving the issue by setting ScrollingCacheEnabled programmatic and within the AXML file to both true and false just to see if that is an issue. It seems not to have any kind of an effect.
Second issue: Focus Loss
When I touch the EditText within this same ListView I get the keyboard to appear but I loose the focus on the field and it needs to get touched again to get focus and it allows me to be written.
Attempted solution
I fiddled with setting the fields focusable, Focusavle in toucmode, touchable and whatnot but came out empty handed.
Honestly I am quite new to android and to programming on this level as well but I tried my best on this. I might have just missed something due to lack of knowledge or it's just something somebody with more experience could tackle and solve.
The second issue isn't that bad for now (still after filling out quite a number of fields it does get tiring to set it twice...) but the scrolling issue is a must.
I think you problem relates to that you forget to update the items in the Adapters when you alter the Views containing them. So you need to wire up the events from the Views to update the items.
Why? If you look carefully at your Adapter for you ListView you populate the convertView with the values of GetItem(position). So if that item does not reflect the changes you have made to the View you are bound to get the initial values of that item.
So what you need to do is to hook up SpinnerValue.ItemSelected and all the other Views which can be altered events, so that the items in the Adapter get their values updated. Remember to only add event handlers when you first create the View. So that is when convertView is null.
Also consider changing the lines:
if (SpinnerValue.Adapter.Count.Equals(2))
{
SpinnerValue.SetSelection(1);
}
To be based on the items in the Adapter rather than setting it to 1 every time.
You focus problem is based in that ListView is not really made for having Views inside of it wanting the focus. Try setting the ListView DecendantFocusability when you instantiate it to DescendantFocusability.AfterDescendants like so:
lstPrevzem.DescendantFocusability = DescendantFocusability.AfterDescendants;
I resolved the issue by replacing the listview with LinearLayout and pinning the adapter to it. The "fixed" code is available on pastebin.
Fixed code:
http://pastebin.com/vn3SPrFz
I have a ListView which gets items from a db (using SimpleCursorAdapter). After the list is populated I want to scroll it to a given position. I can't find the right place to do this.
Right now I set a "need to scroll" flag before running the query. Then I check this flag in setViewValue() and if it's set I scroll the list and reset the flag. Although this works, I don't think it's the best way to do it.
Any other ideas about how to perform some actions when a ListView is populated?
Perhaps you're looking for a "scroll-to" like method. Here's a quick reference.
Ok, I think I solved this. Derived my own adapter from SimpleCursorAdapter, overloaded notifyDataSetChanged method so that it scrolls the list when necessary after calling super's method. Looks working.