From f224edf03d718a4b112f0796ab4ad7bb146dfc5d Mon Sep 17 00:00:00 2001 From: Shane Neuville Date: Thu, 29 Aug 2019 15:09:34 -0600 Subject: [PATCH] [Android/iOS] RefreshView (#7214) * Swipe To Refresh * pull in pull to refresh * api changes * Added RefreshView CoreGallery and Gallery Samples (using ScrollView, ListView, CollectionView, etc.) * Code refactoring in RefreshViewRenderer (iOS) * Updated RefreshView Android Renderer * Fixed RefreshView Android samples in Core Gallery * Added initial RefreshView UWP implementation * Added another UWP RefreshView renderer using WinUI NuGet controls (RefreshContainer) * - additional linker settings * - uwp fixes * - disable SkipMicrosoftUIXamlCheckTargetPlatformVersion check * Update .nuspec/Xamarin.Forms.targets * Limited RefreshView in Android to support only content using scroll. Small changes in RefreshView iOS renderer. Updated Core Gallery RefreshView samples. * Fixed Visualizer colors in UWP RefreshView * Added UWP RefreshPullDirection Platform Specific * Small changes in code syntax in iOS renderer. * Removed some unnecessary curly braces . * Register effect provider in iOS RefreshView * Changes in RefreshView UWP Dispose * Added conditional code to manage the refresh control differently if it is iOS 10 or higher. * Fixed error in Android Core Gallery (Linker) Code refactoring and small changes (PR Feedback) * Changes disposing the Android renderer * - fix SkipMicrosoftUIXamlCheckTargetPlatformVersion so it can be turned off * Removed UWP RefreshView renderer and Platform Specific * - remove winui from nuspec * - remove skip checks from targets * - remove XamlControlsResources * - remove skip check on UAP platform * Revert changes in Android Core Gallery manifiest * Revert unnecessary space in UAP Platform csproj * Removed unnecessary new line in UWP Resources * Simplified RefreshView iOS Renderer. fixes #5882 --- Stubs/Xamarin.Forms.Platform.cs | 4 + ...rms.ControlGallery.WindowsUniversal.csproj | 1 + Xamarin.Forms.Controls/CoreGallery.cs | 3 + .../CoreGalleryPages/CoreGalleryPage.cs | 14 +- .../RefreshViewCoreGalleyPage.cs | 120 ++++++++ .../GalleryPages/GalleryBuilder.cs | 2 +- .../RefreshCollectionViewGallery.xaml | 36 +++ .../RefreshCollectionViewGallery.xaml.cs | 14 + .../RefreshLayoutGallery.xaml | 48 ++++ .../RefreshLayoutGallery.xaml.cs | 14 + .../RefreshListViewGallery.xaml | 48 ++++ .../RefreshListViewGallery.xaml.cs | 14 + .../RefreshScrollViewGallery.xaml | 47 +++ .../RefreshScrollViewGallery.xaml.cs | 14 + .../RefreshViewGallery.cs | 99 +++++++ .../Xamarin.Forms.Controls.csproj | 6 +- .../WindowsSpecific/RefreshView.cs | 40 +++ Xamarin.Forms.Core/RefreshView.cs | 81 ++++++ .../TestAttributes.cs | 5 + .../Properties/AssemblyInfo.cs | 1 + .../Renderers/RefreshViewRenderer.cs | 270 ++++++++++++++++++ .../Xamarin.Forms.Platform.Android.csproj | 1 + .../Properties/AssemblyInfo.cs | 1 + .../Renderers/RefreshViewRenderer.cs | 215 ++++++++++++++ .../Xamarin.Forms.Platform.iOS.csproj | 1 + .../Xamarin.Forms.Platform.cs | 4 + 26 files changed, 1098 insertions(+), 5 deletions(-) create mode 100644 Xamarin.Forms.Controls/CoreGalleryPages/RefreshViewCoreGalleyPage.cs create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml.cs create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml.cs create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml.cs create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshScrollViewGallery.xaml create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshScrollViewGallery.xaml.cs create mode 100644 Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshViewGallery.cs create mode 100644 Xamarin.Forms.Core/PlatformConfiguration/WindowsSpecific/RefreshView.cs create mode 100644 Xamarin.Forms.Core/RefreshView.cs create mode 100644 Xamarin.Forms.Platform.Android/Renderers/RefreshViewRenderer.cs create mode 100644 Xamarin.Forms.Platform.iOS/Renderers/RefreshViewRenderer.cs diff --git a/Stubs/Xamarin.Forms.Platform.cs b/Stubs/Xamarin.Forms.Platform.cs index 3625945cf98..3fae7482063 100644 --- a/Stubs/Xamarin.Forms.Platform.cs +++ b/Stubs/Xamarin.Forms.Platform.cs @@ -154,6 +154,10 @@ internal class _PageRenderer { } [RenderWith (typeof (PhoneMasterDetailRenderer))] #endif internal class _MasterDetailPageRenderer { } +#if !TIZEN4_0 + [RenderWith(typeof(RefreshViewRenderer))] +#endif + internal class _RefreshViewRenderer { } } diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj b/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj index afe63e73c81..91d6c915a43 100644 --- a/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj @@ -24,6 +24,7 @@ Always win10-arm;win10-arm-aot;win10-x86;win10-x86-aot;win10-x64;win10-x64-aot False + true true diff --git a/Xamarin.Forms.Controls/CoreGallery.cs b/Xamarin.Forms.Controls/CoreGallery.cs index 915cbb307ad..c1316c50d1c 100644 --- a/Xamarin.Forms.Controls/CoreGallery.cs +++ b/Xamarin.Forms.Controls/CoreGallery.cs @@ -11,6 +11,7 @@ using Xamarin.Forms.PlatformConfiguration.iOSSpecific; using Xamarin.Forms.Controls.GalleryPages.VisualStateManagerGalleries; using Xamarin.Forms.Controls.Issues; +using Xamarin.Forms.Controls.GalleryPages.RefreshViewGalleries; namespace Xamarin.Forms.Controls { @@ -337,6 +338,8 @@ public override string ToString() new GalleryPageFactory(() => new ProgressBarCoreGalleryPage(), "ProgressBar Gallery"), new GalleryPageFactory(() => new MaterialProgressBarGallery(), "ProgressBar & Slider Gallery (Material)"), new GalleryPageFactory(() => new MaterialActivityIndicatorGallery(), "ActivityIndicator Gallery (Material)"), + new GalleryPageFactory(() => new RefreshViewGallery(), "RefreshView Gallery"), + new GalleryPageFactory(() => new RefreshViewCoreGalleryPage(), "RefreshView Core Gallery"), new GalleryPageFactory(() => new ScrollGallery(), "ScrollView Gallery"), new GalleryPageFactory(() => new ScrollGallery(ScrollOrientation.Horizontal), "ScrollView Gallery Horizontal"), new GalleryPageFactory(() => new ScrollGallery(ScrollOrientation.Both), "ScrollView Gallery 2D"), diff --git a/Xamarin.Forms.Controls/CoreGalleryPages/CoreGalleryPage.cs b/Xamarin.Forms.Controls/CoreGalleryPages/CoreGalleryPage.cs index e00770ad2af..3f64475e6ff 100644 --- a/Xamarin.Forms.Controls/CoreGalleryPages/CoreGalleryPage.cs +++ b/Xamarin.Forms.Controls/CoreGalleryPages/CoreGalleryPage.cs @@ -45,7 +45,14 @@ internal CoreGalleryPage() Build(Layout); - Content = new ScrollView { AutomationId = "GalleryScrollView", Content = Layout }; + if (SupportsScroll) + Content = new ScrollView { AutomationId = "GalleryScrollView", Content = Layout }; + else + { + var content = new Grid { AutomationId = "GalleryScrollView" }; + content.Children.Add(Layout); + Content = content; + } } protected virtual void InitializeElement(T element) { } @@ -229,6 +236,11 @@ protected virtual bool SupportsFocus get { return true; } } + protected virtual bool SupportsScroll + { + get { return true; } + } + protected void Add(ViewContainer viewContainer) { _viewContainers.Add(viewContainer); diff --git a/Xamarin.Forms.Controls/CoreGalleryPages/RefreshViewCoreGalleyPage.cs b/Xamarin.Forms.Controls/CoreGalleryPages/RefreshViewCoreGalleyPage.cs new file mode 100644 index 00000000000..e84faf7782a --- /dev/null +++ b/Xamarin.Forms.Controls/CoreGalleryPages/RefreshViewCoreGalleyPage.cs @@ -0,0 +1,120 @@ +using System; +using System.Windows.Input; +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls +{ + [Preserve(AllMembers = true)] + internal class RefreshViewCoreGalleryPage : CoreGalleryPage + { + protected override bool SupportsFocus + { + get { return false; } + } + + protected override bool SupportsScroll + { + get { return false; } + } + + protected override void InitializeElement(RefreshView element) + { + base.InitializeElement(element); + + BindingContext = new RefreshCoreGalleryViewModel(); + + element.Content = CreateContent(); + element.SetBinding(RefreshView.CommandProperty, "RefreshCommand"); + element.SetBinding(RefreshView.IsRefreshingProperty, "IsRefreshing"); + } + + protected override void Build(StackLayout stackLayout) + { + base.Build(stackLayout); + + var refreshColorContainer = new ViewContainer(Test.RefreshView.RefreshColor, new RefreshView + { + Content = CreateContent(), + RefreshColor = Color.Red + }); + + refreshColorContainer.View.SetBinding(RefreshView.CommandProperty, "RefreshCommand"); + refreshColorContainer.View.SetBinding(RefreshView.IsRefreshingProperty, "IsRefreshing"); + + Add(refreshColorContainer); + } + + ScrollView CreateContent() + { + var scrollView = new ScrollView + { + BackgroundColor = Color.Green, + HeightRequest = 250 + }; + + var content = new Grid(); + + var refreshLabel = new Label + { + HorizontalOptions = LayoutOptions.Center, + VerticalOptions = LayoutOptions.Center, + TextColor = Color.White + }; + + refreshLabel.SetBinding(Label.TextProperty, "Info"); + content.Children.Add(refreshLabel); + scrollView.Content = content; + + return scrollView; + } + } + + [Preserve(AllMembers = true)] + public class RefreshCoreGalleryViewModel : BindableObject + { + const int RefreshDuration = 1; + + private bool _isRefresing; + private string _info; + + public RefreshCoreGalleryViewModel() + { + Info = "RefreshView (Pull To Refresh)"; + } + + public bool IsRefreshing + { + get { return _isRefresing; } + set + { + _isRefresing = value; + OnPropertyChanged(); + } + } + + public string Info + { + get { return _info; } + set + { + _info = value; + OnPropertyChanged(); + } + } + + public ICommand RefreshCommand => new Command(ExecuteRefresh); + + private void ExecuteRefresh() + { + IsRefreshing = true; + + Device.StartTimer(TimeSpan.FromSeconds(RefreshDuration), () => + { + IsRefreshing = false; + Info = "Refreshed (Pull To Refresh again)"; + return false; + }); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/GalleryBuilder.cs b/Xamarin.Forms.Controls/GalleryPages/GalleryBuilder.cs index eb9507714cf..c68badb2e71 100644 --- a/Xamarin.Forms.Controls/GalleryPages/GalleryBuilder.cs +++ b/Xamarin.Forms.Controls/GalleryPages/GalleryBuilder.cs @@ -7,7 +7,7 @@ public static class GalleryBuilder public static Button NavButton(string galleryName, Func gallery, INavigation nav) { var automationId = System.Text.RegularExpressions.Regex.Replace(galleryName, " |\\(|\\)", string.Empty); - var button = new Button { Text = $"{galleryName}", AutomationId = automationId, FontSize = 10, HeightRequest = 30 }; + var button = new Button { Text = $"{galleryName}", AutomationId = automationId, FontSize = 10, HeightRequest = Device.RuntimePlatform == Device.Android ? 40 : 30 }; button.Clicked += (sender, args) => { nav.PushAsync(gallery()); }; return button; } diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml new file mode 100644 index 00000000000..f94bd0fda8d --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml.cs new file mode 100644 index 00000000000..273136068cc --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshCollectionViewGallery.xaml.cs @@ -0,0 +1,14 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.RefreshViewGalleries +{ + [Preserve(AllMembers = true)] + public partial class RefreshCollectionViewGallery : ContentPage + { + public RefreshCollectionViewGallery() + { + InitializeComponent(); + BindingContext = new RefreshViewModel(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml new file mode 100644 index 00000000000..d9f48dede07 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml.cs new file mode 100644 index 00000000000..f1f04db5707 --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshLayoutGallery.xaml.cs @@ -0,0 +1,14 @@ +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls.GalleryPages.RefreshViewGalleries +{ + [Preserve(AllMembers = true)] + public partial class RefreshLayoutGallery : ContentPage + { + public RefreshLayoutGallery() + { + InitializeComponent(); + BindingContext = new RefreshViewModel(); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml new file mode 100644 index 00000000000..b3ee912454a --- /dev/null +++ b/Xamarin.Forms.Controls/GalleryPages/RefreshViewGalleries/RefreshListViewGallery.xaml @@ -0,0 +1,48 @@ + + + + +