public static async Task AnimateToItemAsync(ListViewBase list, object targetItem, ScrollToPosition scrollToPosition) { var scrollViewer = list.GetFirstDescendant <ScrollViewer>(); if (scrollViewer == null) { // If ScrollViewer is not found, do nothing. return; } // ScrollToItemAsync will only scroll to the item if it actually exists in the list (that is, it has been // been realized and isn't just a virtual item) if (await ScrollToItemAsync(list, targetItem, scrollViewer, scrollToPosition)) { // Happy path; the item was already realized and we could just scroll to it return; } // This is the unhappy path. Because of virtualization, the item has not actually been created yet. // So we make our best guess about the location of the item var targetPoint = await GetApproximateTargetAsync(list, scrollViewer, targetItem); // And then we scroll toward that position. The interruptCheck parameter will be run as we're scrolling // to see if the item exists yet; if it does, AnimateToOffsetAsync will be canceled and we'll finish // off with a smooth scroll to the item await AnimateToOffsetAsync(scrollViewer, targetPoint.X, targetPoint.Y, async() => await ScrollToItemAsync(list, targetItem, scrollViewer, scrollToPosition)); }
public static (int firstVisibleItemIndex, int lastVisibleItemIndex, int centerItemIndex) GetVisibleIndexes(ListViewBase listViewBase, ItemsLayoutOrientation itemsLayoutOrientation) { int firstVisibleItemIndex = -1; int lastVisibleItemIndex = -1; int centerItemIndex = -1; var scrollViewer = listViewBase.GetFirstDescendant <ScrollViewer>(); var presenters = listViewBase.GetChildren <ListViewItemPresenter>(); if (presenters != null || scrollViewer == null) { int count = 0; foreach (ListViewItemPresenter presenter in presenters) { if (CollectionViewExtensions.IsListViewItemVisible(presenter, scrollViewer, itemsLayoutOrientation)) { if (firstVisibleItemIndex == -1) { firstVisibleItemIndex = count; } lastVisibleItemIndex = count; } count++; } centerItemIndex = (lastVisibleItemIndex + firstVisibleItemIndex) / 2; } return(firstVisibleItemIndex, lastVisibleItemIndex, centerItemIndex); }
async Task JumpTo(ListViewBase list, object targetItem, ScrollToPosition scrollToPosition) { var tcs = new TaskCompletionSource <object>(); void ViewChanged(object s, ScrollViewerViewChangedEventArgs e) => tcs.TrySetResult(null); var scrollViewer = list.GetFirstDescendant <ScrollViewer>(); try { scrollViewer.ViewChanged += ViewChanged; if (scrollToPosition == ScrollToPosition.Start) { list.ScrollIntoView(targetItem, ScrollIntoViewAlignment.Leading); } else if (scrollToPosition == ScrollToPosition.MakeVisible) { list.ScrollIntoView(targetItem, ScrollIntoViewAlignment.Default); } else { // Center and End are going to be more complicated. } await tcs.Task; } finally { scrollViewer.ViewChanged -= ViewChanged; } }
public static async Task JumpToItemAsync(ListViewBase list, object targetItem, ScrollToPosition scrollToPosition) { var scrollViewer = list.GetFirstDescendant <ScrollViewer>(); var tcs = new TaskCompletionSource <object>(); Func <Task> adjust = null; async void ViewChanged(object s, ScrollViewerViewChangedEventArgs e) { if (e.IsIntermediate) { return; } scrollViewer.ViewChanged -= ViewChanged; if (adjust != null) { // Handle adjustments for non-natively supported scroll positions await adjust(); } tcs.TrySetResult(null); } try { scrollViewer.ViewChanged += ViewChanged; switch (scrollToPosition) { case ScrollToPosition.MakeVisible: list.ScrollIntoView(targetItem, ScrollIntoViewAlignment.Default); break; case ScrollToPosition.Start: list.ScrollIntoView(targetItem, ScrollIntoViewAlignment.Leading); break; case ScrollToPosition.Center: list.ScrollIntoView(targetItem, ScrollIntoViewAlignment.Leading); adjust = () => AdjustToCenterAsync(list, scrollViewer, targetItem); break; case ScrollToPosition.End: list.ScrollIntoView(targetItem, ScrollIntoViewAlignment.Leading); adjust = () => AdjustToEndAsync(list, scrollViewer, targetItem); break; } await tcs.Task; } finally { scrollViewer.ViewChanged -= ViewChanged; } }
async Task AnimateTo(ListViewBase list, object targetItem, ScrollToPosition scrollToPosition) { var scrollViewer = list.GetFirstDescendant <ScrollViewer>(); var targetContainer = list.ContainerFromItem(targetItem) as UIElement; if (targetContainer == null) { var horizontalOffset = scrollViewer.HorizontalOffset; var verticalOffset = scrollViewer.VerticalOffset; await JumpTo(list, targetItem, scrollToPosition); targetContainer = list.ContainerFromItem(targetItem) as UIElement; await ChangeViewAsync(scrollViewer, horizontalOffset, verticalOffset, true); } if (targetContainer == null) { // Did not find the target item anywhere return; } // TODO hartez 2018/10/04 16:37:35 Okay, this sort of works for vertical lists but fails totally on horizontal lists. var transform = targetContainer.TransformToVisual(scrollViewer.Content as UIElement); var position = transform?.TransformPoint(new Windows.Foundation.Point(0, 0)); if (!position.HasValue) { return; } // TODO hartez 2018/10/05 17:23:23 The animated scroll works fine vertically if we are scrolling to a greater Y offset. // If we're scrolling back up to a lower Y offset, it just gives up and sends us to 0 (first item) // Works fine if we disable animation, but that's not very helpful scrollViewer.ChangeView(position.Value.X, position.Value.Y, null, false); //if (scrollToPosition == ScrollToPosition.End) //{ // // Modify position //} //else if (scrollToPosition == ScrollToPosition.Center) //{ // // Modify position //} //else //{ //} }
internal static void JumpToIndexAsync(ListViewBase list, int index, ScrollToPosition scrollToPosition) { var scrollViewer = list.GetFirstDescendant <ScrollViewer>(); var con = list.ContainerFromIndex(index); if (con is UIElement uIElement) { var width = uIElement.DesiredSize.Width; var current = scrollViewer.HorizontalOffset; var delta = (index * width) - current; scrollViewer.ChangeView(current + delta, scrollViewer.VerticalOffset, scrollViewer.ZoomFactor, true); } }
public static (int firstVisibleItemIndex, int lastVisibleItemIndex, int centerItemIndex) GetVisibleIndexes(this ListViewBase listViewBase, ItemsLayoutOrientation itemsLayoutOrientation, bool goingNext) { int firstVisibleItemIndex = -1; int lastVisibleItemIndex = -1; var itemsPanel = (listViewBase.ItemsPanelRoot as ItemsStackPanel); if (itemsPanel != null) { firstVisibleItemIndex = itemsPanel.FirstVisibleIndex; lastVisibleItemIndex = itemsPanel.LastVisibleIndex; } else { var scrollViewer = listViewBase.GetFirstDescendant <ScrollViewer>(); var presenters = listViewBase.GetChildren <ListViewItemPresenter>(); if (presenters != null || scrollViewer == null) { int count = 0; foreach (ListViewItemPresenter presenter in presenters) { if (IsListViewItemVisible(presenter, scrollViewer, itemsLayoutOrientation)) { if (firstVisibleItemIndex == -1) { firstVisibleItemIndex = count; } lastVisibleItemIndex = count; } count++; } } } double center = (lastVisibleItemIndex + firstVisibleItemIndex) / 2.0; int centerItemIndex = goingNext ? (int)Math.Ceiling(center) : (int)Math.Floor(center); return(firstVisibleItemIndex, lastVisibleItemIndex, centerItemIndex); }
void FindScrollViewer(ListViewBase listView) { var scrollViewer = listView.GetFirstDescendant <ScrollViewer>(); if (scrollViewer != null) { OnScrollViewerFound(scrollViewer); return; } void ListViewLoaded(object sender, RoutedEventArgs e) { var lv = (ListViewBase)sender; lv.Loaded -= ListViewLoaded; FindScrollViewer(listView); } listView.Loaded += ListViewLoaded; }
protected virtual void FindScrollViewer(ListViewBase listView) { var scrollViewer = listView.GetFirstDescendant <ScrollViewer>(); if (scrollViewer != null) { _scrollViewer = scrollViewer; _scrollViewer.ViewChanged += OnScrollViewChanged; return; } void ListViewLoaded(object sender, RoutedEventArgs e) { var lv = (ListViewBase)sender; lv.Loaded -= ListViewLoaded; FindScrollViewer(listView); } listView.Loaded += ListViewLoaded; }
void OnListSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e) { var newSize = e.NewSize; _carouselHeight = newSize.Height; _carouselWidth = newSize.Width; _scrollViewer = ListViewBase.GetFirstDescendant <ScrollViewer>(); if (_scrollViewer != null) { // TODO: jsuarezruiz This breaks the ScrollTo override. Review it. _scrollViewer.ViewChanging += OnScrollViewChanging; _scrollViewer.ViewChanged += OnScrollViewChanged; } UpdateItemsSource(); UpdateItemTemplate(); UpdateIsSwipeEnabled(); UpdateIsBounceEnabled(); }
protected override void FindScrollViewer(ListViewBase listView) { var scrollViewer = listView.GetFirstDescendant <ScrollViewer>(); if (scrollViewer != null) { _scrollViewer = scrollViewer; // TODO: jsuarezruiz This breaks the ScrollTo override. Review it. _scrollViewer.ViewChanging += OnScrollViewChanging; _scrollViewer.ViewChanged += OnScrollViewChanged; return; } void ListViewLoaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) { var lv = (ListViewBase)sender; lv.Loaded -= ListViewLoaded; FindScrollViewer(listView); } listView.Loaded += ListViewLoaded; }