smoothScrollToPosition does not scroll - android

I have a listfragment, whose listview is loaded using a cursorloader from the contacts provider. An onScrollListener is also registered.
Requirement : The scroll listener is triggered whenever the user does a scroll through the UI. But i need to trigger it automatically when the listview is loaded for the first time as well.
Problem : I have tried using smoothScrollToPosition(0) in onActivityCreated() to trigger the scroll, but it does not scroll no matter what position i provide as parameter. Based on some other posts on SO, I have tried using setSelection() instead, which does work, but does not trigger the scroll listener. I have tried the post method as well as below, but it makes no difference :
v.post(new Runnable() {
#Override
public void run() {
v.smoothScrollToPosition(0);
}
});
Any other way to trigger a scroll automatically?

Related

confused about viewTreeObserver.addOnGlobalLayoutListener usage

I am altering a recyclerview and would like to be notified of when that update is finished. I read How to know when the RecyclerView has finished laying down the items? that you are notified in the callback to addOnGlobalLayoutListener, but that is called too many times unless you add the last line.
Here is what I tried:
my_rv.viewTreeObserver.addOnGlobalLayoutListener {
calculate(myAdapter.getItems())
my_rv.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
in order for the last line to compile, my fragment needs to override onGlobalLayout. What am I supposed to put in onGlobalLayout? I never see that callback even called.
It's because in your calculate method you change the layout, like setting text, setting image resource, etc. so in the first call you need to remove the listener to avoid listening to the next GlobalLayout events.
and it is better to remove removeOnGlobalLayoutListener in first line:
my_rv.viewTreeObserver.addOnGlobalLayoutListener {
my_rv.viewTreeObserver.removeOnGlobalLayoutListener(this)
calculate(myAdapter.getItems())
}

RecyclerView scrolls to top every time ContentProvider calls getContentResolver.notifyChange(uri, observer=null)?

I have a RecyclerView that contains a ListView, and every time the back end database changes (via the update() method in the ContentProvider), the ContentProvider calls getContext().getContentResolver().notifyChange(uri, null), which makes the RecyclerView scroll to top.
I understand that if we are updating the view in the adapter, we can just call notifyDatasetChanged() and then smooth scroll to the current position in the activity. But since I've already been only calling notifyDatasetChanged() in the Adapter, and this problem is caused the notifyChange() in the ContentProvider, does anyone have an idea how to solve it?
Also I have a LoaderManager in my Activity, and no ContentObserver is needed.

Xamarin Forms Listview with RecycleElement CachingStrategy not properly updating binding context

I'm currently struggling with an issue at work, we have a ListView with the RecycleElement strategy but this is causing unexpected behaviors in the ViewCells.
When I tap on a ViewCell the first thing that happens is that the OnBindingContextChanged event is called, this happens Before the OnTapped event get's called. After pressing the ViewCell the app navigates to a different view where the user can change it's corresponding data. When the user navigates back to the previous page what should happen is that the new data that was entered should be presented in the ViewCell but this does not happen, the OnBindingContextChanged event doesn't even get fired even through I am able to get a CollectionChanged event from the ObservableCollection object which is bounded to the ListView's ItemsSource.
When I remove the CachingStrategy I get the expected behavior from the ListView ViewCells, when the user pressed the ViewCell nothing happens but when the user goes back to the original page the OnBindingContextChanged event is called and the data is properly updated.
We need the Recycle Strategy for the app's performance since it can happen that there are hundreds of items in the ListView and the app needs to stay fully responsive even when scrolling through all those items.
There isn't to much code I can share but here is what I can share
The XAML ListView definition
<ListView x:Name="TouchformList"
CachingStrategy="RecycleElement"
ItemsSource="{Binding DisplayItems}"
ItemTemplate="{StaticResource TouchformTemplateSelector}"
HasUnevenRows="True"
ItemSelected="Handle_ItemSelected"
SeparatorVisibility="None" />
DisplayItems is an ObservableCollection
BaseTouchformItem extends the ObservableObject class
Inside the ViewModel the DisplayItems are exposed like this
private ObservableCollection<BaseTouchformItem> _displayItems = new ObservableCollection<BaseTouchformItem>(); //This object is never re-assigned elsewhere
public ObservableCollection<BaseTouchformItem> DisplayItems
{
get
{
return _displayItems;
}
}
Adding items to the DisplayItems is no issue and those appear as expected.
Changing an item by simply calling DisplayItems[lastSelectedItem] = touchformItem; does raise a CollectionChanged event in the ObservableCollection as expected but when the RecycleElement strategy is active this does not propagate through to the ViewCell.
The only way I was able to get this to work was via this bad method,
DisplayItems.RemoveAt(lastSelectedItem);
await Task.Delay(50);//Horrible 'fix'
DisplayItems.Insert(lastSelectedItem, touchformItem);
But that obviously causes a UI 'glitch' by quickly removing an item and then re-adding it.
Is this potentially a bug in the ListView or is there something else going on?
I found the issue, for some reason the Recycle strategy doesn't like it when I swap out an object inside of the ObservableCollection, it just ignores whats happening and keeps the list as is.
The way the VM was setup was that it would re-create each item every time some data changed instead of just updating the item itself (thus making the bindings irrelevant as well), I changed it so that it updates the item itself and doesn't re-create the same item again and now it is working as expected.

Android - how to stop ListView.setAdapter(); interrupting scroll view?

I've got a ListView with a method (public ArrayAdapter<String> populateListView(){}) to update the Adapter. Every 500ms I call lv.setAdapter(populateListView();. This works, but if I'm scrolling down the ListView, when the method is called it resets my view and automatically scrolls me to the top. So if I'm 80% down my ListView, when the method is called I'm reset to 0%.
How do I continually populate my ListView without resetting the scroll position?
I've already tried calling lv.getScrollY(); before setting the adapter and then lv.setScrollY(); but this doesn't help. I've also tried calling lv.scrollTo(0, scrollY); but this doesn't help.
How do I stop resetting the scroll position when updating the adapter?
Try updating the items in the adapter and call adapter.notifyDataSetChanged() instead of creating a new adapter.
Example:
adapter.replaceItems(yourNewListWithData);
adapter.notifyDataSetChanged();
You have to implement the replaceItems method yourselves.
public void replaceItems(List<? extends E> newItems) {
entries.clear();
entries.addAll(newItems);
}

smoothScrollToPosition after notifyDataSetChanged not working in android

I've got a custom Adapter for a ListView setup and working ok. On a button click something is changed in the underlying data, so a notifyDataSetChanged is required to refresh the ListView. Fine. But I also want the ListView to scroll to the line where the change occurred. For this I call smoothScrollToPosition immediately after the notifyDataSetChanged. And that is not working.
If I do not call notifyDataSetChanged then the scroll works, so the notify blocks the scroll. I'm probably having a fight with events being processed in the future. Can anybody give me a pointer on what is going wrong?
Use the post() method to wait for the list to finish updating after you call notifyDataSetChanged():
adapter.notifyDataSetChanged();
list.post( new Runnable() {
#Override
public void run() {
//call smooth scroll
}
});
I've tried the dmon's example code and I see it not always working.
Actually I've found another approach to perform scrolling:
adapter.notifyDataSetChanged();
channelsListView.setSelection(scrollPos); // it works without smoothScrollToPositionFromTop(..) or smoothScrollToPosition() methods call.
I found the main idea to use above method after this answer reading:
https://stackoverflow.com/a/20997828/2133585

Categories

Resources