Provide a ListView Scrolled event identical to the ScrollView. This will allow apps to apply animations like parallax on the ListView Header for example.
e.g.
In order to facilitate this an Event is added to the ListView called Scrolled with the same event args as a ScrollView.
public event EventHandler<ScrolledEventArgs> Scrolled { add; remove; }
This will allow apps to apply animations on scroll like parallax on the ListView Header for example.
Posts
Im not actually sure the Scroll offsets are readily available on all platforms. I mean Im sure estimates are but Im not sure we can actually get proper numbers that will reliably monotonically increase as you scroll down even when estimated values end up being wrong.
A quick spike providing this is possible on iOS/UWP/Android would be enough to get a +1 for me.
I don't believe Android provides scroll delta on ListView. I've seen hacky solutions that did not work for everyone. If you are trying to create a parallax effect, then you're looking at
CoordinatorLayout
and its friends as suggested here.A quick googling seems to confirm Adrian is right, the ListView does not provide this information on Android.
Unless someone else has an idea how to solve that reliably and in a way that wont be a maintenance nightmare I think we will have to reject this proposal.
Ideally I would like to be able to perform animations on the ListView Header based on scrolling. I know there are other use cases for it as well.
I will dig up the apis
https://developer.android.com/reference/android/widget/AbsListView.OnScrollListener.html
That listener provides everything except for scroll delta. If you want visible item changes, then XF already has
ItemAppearing
andItemDisappearing
. Scroll state flags are also useless in my opinion. When implementing a parallax, you probably do not need just a simple Scrolled Y/N flag but also the amount/velocity/etc.That gives when views become visible, not the X/Y offset. Visible view tracking is not what the ScrolledEventArgs does.
True but it could be computed but that might be expensive.
It can't be computed without realizing and measuring every cell in the UnevenRows case
I did something a long time ago that works "well enough" for me in the Android case. See here https://github.com/programmation/AdvancedCustomRendererTest/blob/master/Droid/Renderers/AdvancedListViewRenderer.cs#L124.
The essence of the idea (which I got from somewhere on the interwebs but I regret I forgot where) is that you measure the vertical offset of the first child of the
ListView
. It's not quite the same accuracy as the iOS scroll position, but it's easily good enough to do what we need.I'm sorry I have no idea how to do the equivalent (or if it's even possible) in Windows.
How does that work once you start recycling?
Ha, good question! I am on an old version of Xamarin Forms in the project from which I extracted that code, so I'm sorry I don't know. However since it's calling the Android API on the underlying
Android.Widget.ListView
usingGetChildAt(0)
to get the first element in theListView
I would hope that all the dots would join up internally and everything would still work.Yeah that wont work anymore
We could still keep track of the top element internally though, no?
not really, there is not guarantee that the ListView will start at the top. The top cell may never actually be displayed.
stackoverflow.com/questions/3014089/maintain-save-restore-scroll-position-when-returning-to-a-listview#comment68687300_3035521 says the
GetChildAt(0)
technique works on wearables. Do they use recycling?GetChildAt(0) will return the 0th child of the listview which is currently realized. Its Y position will be largely unrelated to the current Y position of the list as the whole thing is just kind of faked on a sliding surface.
While it will work in some limited cases, I can't imagine how it could possibly work with larger truly virtualized lists. At this point though, I guess someone will have to just try and see!
I'll have a go and report back.
We do not believe this is possible. I am rejecting the proposal but will leave it open in case anyone comes back with a proof of concept showing we can make it work reliably.
We have now implemented this on iOS and UWP, and are currently working on a (reliable!) Android implementation.
Once we have this working on Android, will post back here.
@Velocity will you put up on github?
@DH_HA1 Sure thing, we got an initial version working on Android this morning but it still needs more work.
Once it's stabilized, will add it to our XF Controls repo.
@DH_HA1 @TheRealJasonSmith OK, we now have a stabilized version of our extended ListView with scroll events.
Please see portable control here and renderers below.
This is working great on all three platforms. Tested with both
RetainElement
andRecycleElement
caching strategies, HasUnevenRows=true/false. We're now using it to achieve a parallax effect behind a scrollingListView
.iOS and UWP implementations are a breeze. Android is a little more tricky as native AbsListView has no concept of scroll events, but with a little bit of math and view tracking we can do a fairly nice job. Added total offset calculation and compensation for display density.
Kudos to Budius on this StackOverflow post. Was able to base the view tracking and offset calculation engine on his Java implementation.
@Velocity Budius' comment at the end of the SO post is telling. Perhaps the Android
ListView
widget is simply the wrong one to use altogether. I know we're limited by Xamarin.Forms' original choices, and I think your contribution is an excellent workaround, but we should probably be concentrating on scrolling views that are based onUICollectionView
,RecyclerView
and whatever it is in WinPhone instead, rather than flogging the deadUITableView
/ListView
horses. I've even seen some in Swift/Obj-C development circles recommend abandoningUITableView
now too.I do agree on some respects, however that really is a separate issue. It could be argued that
RecyclerView
is a worthy replacement for AbsListView, however there is nothing wrong with usingUITableView
on iOS andListView
on UWP. Their collection view cousinsUICollectionView
andGridView
work great, but are not designed as a native list view replacement.I still agree that a separate collection view is needed which is why I proposed it in a separate thread (Note, we have also built this and is working). The purpose of this request is simply to extend an existing control already available within Xamarin.Forms.
@Velocity thanks so much for this, I was able to create a sticky header on Xamarin.Android/Forms without any 3rd party implementation! (This is a task that took me 4 days to complete.)
@Velocity Thanks dude - your code helped me a lot understanding the android side of it - I've now managed to extend the returned eventargs to include IsAtBottom parameter and using a 'firstVisibleItem + visibleItemCount == totalItemCount' condition in the OnScroll() to set it and send via your framework. Works a treat, great stuff!
I always thought nesting ListView into a ScrollView was a big nono but it actually worked pretty well for me. you can rely on the Scrolled event from the ScrollView instead in this nested setup. I was able to achieve the Parallax effect using this method. Note that the ListView's background color is set to transparent and I've reserved 200px high StackLayout in the header of the ListView. In the background of the ListView, there I placed the .
The scrolled event doesn't work well when you have a footer section in the listview for some reason. Therefore, it was commented out in the Xaml above. The event handler example is as below. Just an example for you, that may not be a Parallax algorithm but this was good enough for me.
If anyone would like the code for the custom Android renderer with scroll events, here it is.
https://gist.github.com/velocitysystems/a446609dcfe2a9224a2d20ab41864909