From 0918df146d8b050a3826054200e7643b89b36b7d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Javier=20Su=C3=A1rez=20Ruiz?= Date: Tue, 29 Oct 2019 12:31:39 +0100 Subject: [PATCH] [Android] Fixed issue refreshing CollectionView using ScrollView inside DataTemplate (#8224) fixes #8198 * Fixed issue 8198 - ScrollView at CollectionView at RefreshView always leads to Pull-To-Refresh * Added instructions to the Issue8198 * Added support for WebView on Android to align functionality with iOS * Added more RefreshView Core Gallery samples * Updated new samples * Updated instructions text --- .../Issue8198.cs | 114 +++++++++++++++++++++ .../Xamarin.Forms.Controls.Issues.Shared.projitems | 1 + .../RefreshCarouselViewGallery.xaml | 47 +++++++++ .../RefreshCarouselViewGallery.xaml.cs | 14 +++ .../RefreshCollectionViewGallery.xaml | 28 ++--- .../RefreshListViewGallery.xaml | 28 ++--- .../RefreshViewGalleries/RefreshViewGallery.cs | 24 ++++- .../RefreshWebViewGallery.xaml | 19 ++++ .../RefreshWebViewGallery.xaml.cs | 76 ++++++++++++++ .../Xamarin.Forms.Controls.csproj | 6 ++ .../Renderers/RefreshViewRenderer.cs | 11 +- 11 files changed, 336 insertions(+), 32 deletions(-) create mode 100644 Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8198.cs create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml.cs create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml.cs diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8198.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8198.cs new file mode 100644 index 0000000..5c8e9e1 --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8198.cs @@ -0,0 +1,114 @@ +using System; +using System.Threading.Tasks; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; + +#if UITEST +using Xamarin.Forms.Core.UITests; +using Xamarin.UITest; +using NUnit.Framework; +#endif + +namespace Xamarin.Forms.Controls.Issues +{ +#if UITEST + [Category(UITestCategories.RefreshView)] +#endif + [Preserve(AllMembers = true)] + [Issue(IssueTracker.Github, 8198, "ScrollView at CollectionView at RefreshView always leads to Pull-To-Refresh", PlatformAffected.Android)] + public class Issue8198 : TestContentPage + { + RefreshView _refreshView; + Command _refreshCommand; + + protected override void Init() + { + Title = "Issue 8198"; + + var layout = new StackLayout(); + + var instructions = new Label + { + BackgroundColor = Color.Black, + TextColor = Color.White, + Text = "Scroll the CollectionView to end, lift finger off screen, and then try to scroll up again. If the Refresh Indicator does not appear until it reaches the top, the test has passed." + }; + + _refreshCommand = new Command(async (parameter) => + { + if (!_refreshView.IsRefreshing) + { + throw new Exception("IsRefreshing should be true when command executes"); + } + + if (parameter != null && !(bool)parameter) + { + throw new Exception("Refresh command incorrectly firing with disabled parameter"); + } + + await Task.Delay(2000); + _refreshView.IsRefreshing = false; + }); + + _refreshView = new RefreshView + { + Command = _refreshCommand + }; + + var collectionView = new CollectionView + { + ItemTemplate = GetDataTemplate(), + ItemsSource = new string[] + { + "Item 1", + "Item 2", + "Item 3", + "Item 4", + "Item 5", + "item 6", + "Item 7", + "Item 8", + "Item 9", + "Item 10", + "Item 11", + "item 12", + "Item 13", + "Item 14", + "Item 15", + "Item 16", + "Item 17", + "Item 18", + "Item 19", + "Item 20" + } + }; + + _refreshView.Content = collectionView; + + layout.Children.Add(instructions); + layout.Children.Add(_refreshView); + + Content = layout; + } + + DataTemplate GetDataTemplate() + { + var template = new DataTemplate(() => + { + var scroll = new ScrollView(); + var grid = new Grid(); + grid.RowDefinitions.Add(new RowDefinition() { Height = 40 }); + + var cell = new Label(); + cell.SetBinding(Label.TextProperty, "."); + cell.FontSize = 20; + cell.BackgroundColor = Color.LightBlue; + grid.Children.Add(cell, 0, 0); + + scroll.Content = grid; + return scroll; + }); + return template; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems index 8f14504..05a80a1 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems @@ -1138,6 +1138,7 @@ Issue7886.xaml + diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml new file mode 100644 index 0000000..30f1de4 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml.cs new file mode 100644 index 0000000..ce1e8df --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCarouselViewGallery.xaml.cs @@ -0,0 +1,14 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.RefreshViewGalleries +{ + [Preserve(AllMembers = true)] + public partial class RefreshCarouselViewGallery : ContentPage + { + public RefreshCarouselViewGallery() + { + InitializeComponent(); + BindingContext = new RefreshViewModel(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml index f94bd0f..51a9f1b 100644 --- a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml @@ -15,19 +15,21 @@ ItemsSource="{Binding Items}"> - - - - - - - + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml index b3ee912..5014c60 100644 --- a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml @@ -25,19 +25,21 @@ - - - - - - - + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshViewGallery.cs b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshViewGallery.cs index d23f527..ac6bed1 100644 --- a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshViewGallery.cs +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshViewGallery.cs @@ -11,17 +11,39 @@ namespace Xamarin.Forms.Controls.GalleryPages.RefreshViewGalleries public RefreshViewGallery() { Title = "RefreshView Gallery"; + + var button = new Button + { + Text = "Enable CarouselView", + AutomationId = "EnableCarouselView" + }; + button.Clicked += ButtonClicked; + Content = new StackLayout { Children = { + button, GalleryBuilder.NavButton("Refresh Layout Gallery", () => new RefreshLayoutGallery(), Navigation), GalleryBuilder.NavButton("Refresh ScrollView Gallery", () => new RefreshScrollViewGallery(), Navigation), GalleryBuilder.NavButton("Refresh ListView Gallery", () => new RefreshListViewGallery(), Navigation), - GalleryBuilder.NavButton("Refresh CollectionView Gallery", () => new RefreshCollectionViewGallery(), Navigation) + GalleryBuilder.NavButton("Refresh CollectionView Gallery", () => new RefreshCollectionViewGallery(), Navigation), + GalleryBuilder.NavButton("Refresh CarouselView Gallery", () => new RefreshCarouselViewGallery(), Navigation), + GalleryBuilder.NavButton("Refresh WebView Gallery", () => new RefreshWebViewGallery(), Navigation) } }; } + + void ButtonClicked(object sender, System.EventArgs e) + { + var button = sender as Button; + + button.Text = "CarouselView Enabled!"; + button.TextColor = Color.Black; + button.IsEnabled = false; + + Device.SetFlags(new[] { ExperimentalFlags.CarouselViewExperimental }); + } } [Preserve(AllMembers = true)] diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml new file mode 100644 index 0000000..aa8259c --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml.cs new file mode 100644 index 0000000..5d9bce7 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshWebViewGallery.xaml.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Windows.Input; +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.RefreshViewGalleries +{ + [Preserve(AllMembers = true)] + public partial class RefreshWebViewGallery : ContentPage + { + public RefreshWebViewGallery() + { + InitializeComponent(); + BindingContext = new RefreshWebViewGalleryViewModel(); + } + } + + [Preserve(AllMembers = true)] + public class RefreshWebViewGalleryViewModel : BindableObject + { + const int RefreshDuration = 2; + + readonly Random _random; + bool _isRefresing; + string _url; + + public RefreshWebViewGalleryViewModel() + { + _random = new Random(); + LoadUrl(); + } + + public bool IsRefreshing + { + get { return _isRefresing; } + set + { + _isRefresing = value; + OnPropertyChanged(); + } + } + + public string Url + { + get { return _url; } + set + { + _url = value; + OnPropertyChanged(); + } + } + + public ICommand RefreshCommand => new Command(ExecuteRefresh); + + void LoadUrl() + { + var urls = new List { "https://dotnet.microsoft.com/apps/xamarin", "https://devblogs.microsoft.com/xamarin/" }; + int index = _random.Next(urls.Count); + Url = urls[index]; + } + + void ExecuteRefresh() + { + IsRefreshing = true; + + Device.StartTimer(TimeSpan.FromSeconds(RefreshDuration), () => + { + LoadUrl(); + + IsRefreshing = false; + + return false; + }); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj b/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj index 5e81105..38e427e 100644 --- a/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj +++ b/Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj @@ -86,6 +86,12 @@ MSBuild:UpdateDesignTimeXaml + + MSBuild:UpdateDesignTimeXaml + + + MSBuild:UpdateDesignTimeXaml + MSBuild:UpdateDesignTimeXaml diff --git a/Xamarin.Forms.Platform.Android/Renderers/RefreshViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/RefreshViewRenderer.cs index 88c7af9..2487ee3 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/RefreshViewRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/RefreshViewRenderer.cs @@ -9,6 +9,7 @@ using Android.Views; using Android.Widget; using Xamarin.Forms.Internals; using AView = Android.Views.View; +using AWebView = Android.Webkit.WebView; namespace Xamarin.Forms.Platform.Android { @@ -170,13 +171,13 @@ namespace Xamarin.Forms.Platform.Android } if(view is RecyclerView recyclerView) - return recyclerView.ScrollY < 0; - - if (view is global::Android.Widget.ScrollView scrollview) - return scrollview.ScrollY < 0; + return recyclerView.ComputeVerticalScrollOffset() > 0; if (view is NestedScrollView nestedScrollView) - return nestedScrollView.ScrollY < 0; + return nestedScrollView.ComputeVerticalScrollOffset() > 0; + + if (view is AWebView webView) + return webView.ScrollY > 0; return true; } -- 2.7.4