From 98cd9b2fe7a97c08326322a3e7d98df45c1c893f Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Sat, 23 Jan 2021 00:55:54 -0300 Subject: [PATCH 1/3] Created LazyView and implemented it on TabView --- .../Pages/Views/TabView/LazyTabPage.xaml | 57 +++++++++++++++++++ .../Pages/Views/TabView/LazyTabPage.xaml.cs | 7 +++ .../Pages/Views/TabView/LazyTestView.xaml | 25 ++++++++ .../Pages/Views/TabView/LazyTestView.xaml.cs | 29 ++++++++++ .../Pages/Views/TabView/NormalTestView.xaml | 11 ++++ .../Views/TabView/NormalTestView.xaml.cs | 16 ++++++ .../ViewModels/Views/TabViewViewModel.cs | 5 +- .../Views/Tabs/LazyTestViewModel.cs | 27 +++++++++ .../Views/Tabs/NormalTestViewModel.cs | 17 ++++++ .../Views/LazyView/BaseLazyView.shared.cs | 32 +++++++++++ .../Views/LazyView/LazyView.shared.cs | 16 ++++++ .../Views/TabView/TabView.shared.cs | 7 +++ 12 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml create mode 100644 samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml.cs create mode 100644 samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml create mode 100644 samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml.cs create mode 100644 samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml create mode 100644 samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml.cs create mode 100644 samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs create mode 100644 samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs create mode 100644 src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs create mode 100644 src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/LazyView.shared.cs diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml new file mode 100644 index 000000000..a08c4ca21 --- /dev/null +++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml.cs new file mode 100644 index 000000000..fe53d1b9c --- /dev/null +++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTabPage.xaml.cs @@ -0,0 +1,7 @@ +namespace Xamarin.CommunityToolkit.Sample.Pages.Views.TabView +{ + public partial class LazyTabPage + { + public LazyTabPage() => InitializeComponent(); + } +} \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml new file mode 100644 index 000000000..6aecbd309 --- /dev/null +++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml.cs new file mode 100644 index 000000000..24fb78a44 --- /dev/null +++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml.cs @@ -0,0 +1,29 @@ +using Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs; +using Xamarin.Forms; + +namespace Xamarin.CommunityToolkit.Sample.Pages.Views.TabView +{ + public partial class LazyTestView : ContentView + { + public LazyTestView() + { + InitializeComponent(); + + Build(); + NormalTestViewModel.Current.LoadedViews += "LazyView Loaded \n"; + } + + void Build() + { + for (var i = 0; i < 117; i++) + { + var box = new BoxView + { + BackgroundColor = i % 2 == 0 ? Color.Blue : Color.Fuchsia + }; + + uniformGrid.Children.Add(box); + } + } + } +} \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml new file mode 100644 index 000000000..2026ef55d --- /dev/null +++ b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml.cs b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml.cs new file mode 100644 index 000000000..f792cf33a --- /dev/null +++ b/samples/XCT.Sample/Pages/Views/TabView/NormalTestView.xaml.cs @@ -0,0 +1,16 @@ +using Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs; +using Xamarin.Forms; + +namespace Xamarin.CommunityToolkit.Sample.Pages.Views.TabView +{ + public partial class NormalTestView : ContentView + { + public NormalTestView() + { + InitializeComponent(); + BindingContext = NormalTestViewModel.Current; + + NormalTestViewModel.Current.LoadedViews += "NormalTestLoaded \n"; + } + } +} \ No newline at end of file diff --git a/samples/XCT.Sample/ViewModels/Views/TabViewViewModel.cs b/samples/XCT.Sample/ViewModels/Views/TabViewViewModel.cs index 076f16b0a..d28e33cef 100644 --- a/samples/XCT.Sample/ViewModels/Views/TabViewViewModel.cs +++ b/samples/XCT.Sample/ViewModels/Views/TabViewViewModel.cs @@ -39,7 +39,10 @@ public class TabViewViewModel : BaseGalleryViewModel "Customize the tabs width"), new SectionModel(typeof(NoContentPage), "Tab without Content", - "Only the TabStrip is visible") + "Only the TabStrip is visible"), + + new SectionModel(typeof(LazyTabPage), "LazyLoadingTab", + "See how you can implement LazyViews that are loaded just when you navigate to them"), }; } } \ No newline at end of file diff --git a/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs new file mode 100644 index 000000000..bb1934888 --- /dev/null +++ b/samples/XCT.Sample/ViewModels/Views/Tabs/LazyTestViewModel.cs @@ -0,0 +1,27 @@ +using Xamarin.CommunityToolkit.ObjectModel; + +namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs +{ + sealed class LazyTestViewModel : ObservableObject + { + public static LazyTestViewModel Current { get; } = new LazyTestViewModel(); + + string title; + + public string Title + { + get => title; + set => SetProperty(ref title, value); + } + + bool loaded; + + public bool Loaded + { + get => loaded; + set => SetProperty(ref loaded, value); + } + + public LazyTestViewModel() => Title = "Lazy Tab Sample"; + } +} diff --git a/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs b/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs new file mode 100644 index 000000000..ff764bcf8 --- /dev/null +++ b/samples/XCT.Sample/ViewModels/Views/Tabs/NormalTestViewModel.cs @@ -0,0 +1,17 @@ +using Xamarin.CommunityToolkit.ObjectModel; + +namespace Xamarin.CommunityToolkit.Sample.ViewModels.Views.Tabs +{ + sealed class NormalTestViewModel : ObservableObject + { + public static NormalTestViewModel Current { get; } = new NormalTestViewModel(); + + string loadedViews; + + public string LoadedViews + { + get => loadedViews; + set => SetProperty(ref loadedViews, value); + } + } +} diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs new file mode 100644 index 000000000..73367a1bb --- /dev/null +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs @@ -0,0 +1,32 @@ +using System; +using System.ComponentModel; +using Xamarin.Forms; + +namespace Xamarin.CommunityToolkit.UI.Views +{ + [EditorBrowsable(EditorBrowsableState.Never)] + public abstract class BaseLazyView : ContentView, IDisposable + { + internal static readonly BindablePropertyKey IsLoadedPropertyKey = BindableProperty.CreateReadOnly(nameof(IsLoaded), typeof(bool), typeof(BaseLazyView), default); + + public static readonly BindableProperty IsLoadedProperty = IsLoadedPropertyKey.BindableProperty; + + public bool IsLoaded => (bool)GetValue(IsLoadedProperty); + + internal void SetIsLoaded(bool isLoaded) => SetValue(IsLoadedPropertyKey, isLoaded); + + public abstract void LoadView(); + + public void Dispose() + { + if (Content is IDisposable disposable) + disposable.Dispose(); + } + + protected override void OnBindingContextChanged() + { + if (Content != null && !(Content is ActivityIndicator)) + Content.BindingContext = BindingContext; + } + } +} \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/LazyView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/LazyView.shared.cs new file mode 100644 index 000000000..d973c461b --- /dev/null +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/LazyView.shared.cs @@ -0,0 +1,16 @@ +using Xamarin.Forms; + +namespace Xamarin.CommunityToolkit.UI.Views +{ + public class LazyView : BaseLazyView where TView : View, new() + { + public override void LoadView() + { + View view = new TView { BindingContext = BindingContext }; + + Content = view; + + SetIsLoaded(true); + } + } +} \ No newline at end of file diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs index c06043930..f82ad8084 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/TabView/TabView.shared.cs @@ -172,6 +172,9 @@ public void Dispose() if (TabItems != null) TabItems.CollectionChanged -= OnTabItemsCollectionChanged; + + var lazyView = (((TabViewItem)contentContainer.CurrentItem).Content as BaseLazyView) ?? (TabItems[SelectedIndex].Content as BaseLazyView); + lazyView?.Dispose(); } public ObservableCollection TabItems { get; set; } @@ -775,6 +778,8 @@ void UpdateSelectedIndex(int position, bool hasCurrentItem = false) var tabViewItem = TabItems[SelectedIndex]; + var lazyView = (currentItem?.Content as BaseLazyView) ?? (tabViewItem?.Content as BaseLazyView); + contentIndex = contentTabItems.IndexOf(currentItem ?? tabViewItem); tabStripIndex = TabItems.IndexOf(currentItem ?? tabViewItem); @@ -788,6 +793,8 @@ void UpdateSelectedIndex(int position, bool hasCurrentItem = false) TabItems[index].IsSelected = false; } + if (!lazyView?.IsLoaded ?? false) + lazyView?.LoadView(); var currentTabItem = TabItems[position]; currentTabItem.SizeChanged += OnCurrentTabItemSizeChanged; UpdateTabIndicatorPosition(currentTabItem); From e8e2512297015360f885a01120f5d47edf59eecc Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Sat, 23 Jan 2021 01:12:32 -0300 Subject: [PATCH 2/3] Added Preserve attribute --- .../Views/LazyView/BaseLazyView.shared.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs index 73367a1bb..84931f0bc 100644 --- a/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs +++ b/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/LazyView/BaseLazyView.shared.cs @@ -1,10 +1,10 @@ using System; -using System.ComponentModel; using Xamarin.Forms; +using Xamarin.Forms.Internals; namespace Xamarin.CommunityToolkit.UI.Views { - [EditorBrowsable(EditorBrowsableState.Never)] + [Preserve(Conditional =true)] public abstract class BaseLazyView : ContentView, IDisposable { internal static readonly BindablePropertyKey IsLoadedPropertyKey = BindableProperty.CreateReadOnly(nameof(IsLoaded), typeof(bool), typeof(BaseLazyView), default); From fd9a11074fcc023551a4639762c08e039ce2d4b6 Mon Sep 17 00:00:00 2001 From: Pedro Jesus Date: Sat, 23 Jan 2021 01:32:51 -0300 Subject: [PATCH 3/3] Update LazyTestView.xaml --- .../XCT.Sample/Pages/Views/TabView/LazyTestView.xaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml index 6aecbd309..68c8ab19a 100644 --- a/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml +++ b/samples/XCT.Sample/Pages/Views/TabView/LazyTestView.xaml @@ -12,14 +12,6 @@ Text="{Binding Title}" TextColor="Black" /> - - - - \ No newline at end of file +