From 77f1fb91f32c2b93ad1befb9e64b6d1faaa1c308 Mon Sep 17 00:00:00 2001 From: Vladislav Antonyuk Date: Fri, 3 May 2024 15:39:17 +0300 Subject: [PATCH] MauiStaggeredCollectionView --- MauiSamples.sln | 8 + MauiStaggeredCollectionView/App.xaml | 14 + MauiStaggeredCollectionView/App.xaml.cs | 11 + MauiStaggeredCollectionView/AppShell.xaml | 15 + MauiStaggeredCollectionView/AppShell.xaml.cs | 9 + MauiStaggeredCollectionView/MainPage.xaml | 26 ++ MauiStaggeredCollectionView/MainPage.xaml.cs | 104 +++++ MauiStaggeredCollectionView/MauiProgram.cs | 17 + .../MauiStaggeredCollectionView.csproj | 31 ++ .../Platforms/Android/AndroidManifest.xml | 6 + .../Platforms/Android/MainActivity.cs | 13 + .../Platforms/Android/MainApplication.cs | 15 + .../Android/Resources/values/colors.xml | 6 + .../Platforms/MacCatalyst/AppDelegate.cs | 9 + .../Platforms/MacCatalyst/Entitlements.plist | 14 + .../Platforms/MacCatalyst/Info.plist | 38 ++ .../Platforms/MacCatalyst/Program.cs | 15 + .../Platforms/MacCatalyst/StagLayout.cs | 54 +++ .../MacCatalyst/StagLayoutFrameHolder.cs | 128 ++++++ .../Platforms/Tizen/Main.cs | 17 + .../Platforms/Tizen/tizen-manifest.xml | 15 + .../Platforms/Windows/App.xaml | 8 + .../Platforms/Windows/App.xaml.cs | 29 ++ .../Platforms/Windows/Package.appxmanifest | 46 ++ .../Platforms/Windows/app.manifest | 15 + .../Platforms/iOS/AppDelegate.cs | 11 + .../Platforms/iOS/Info.plist | 32 ++ .../Platforms/iOS/Program.cs | 15 + .../Platforms/iOS/StagLayout.cs | 54 +++ .../Platforms/iOS/StagLayoutFrameHolder.cs | 128 ++++++ .../Properties/launchSettings.json | 8 + MauiStaggeredCollectionView/README.mdpp | 11 + .../Resources/AppIcon/appicon.svg | 4 + .../Resources/AppIcon/appiconfg.svg | 8 + .../Resources/Images/dotnet_bot.png | Bin 0 -> 69811 bytes .../Resources/Raw/AboutAssets.txt | 15 + .../Resources/Splash/splash.svg | 8 + .../Resources/Styles/Colors.xaml | 45 ++ .../Resources/Styles/Styles.xaml | 426 ++++++++++++++++++ README.mdpp | 2 + SETUP.md | 2 +- md/thankyou.mdpp | 2 +- 42 files changed, 1432 insertions(+), 2 deletions(-) create mode 100644 MauiStaggeredCollectionView/App.xaml create mode 100644 MauiStaggeredCollectionView/App.xaml.cs create mode 100644 MauiStaggeredCollectionView/AppShell.xaml create mode 100644 MauiStaggeredCollectionView/AppShell.xaml.cs create mode 100644 MauiStaggeredCollectionView/MainPage.xaml create mode 100644 MauiStaggeredCollectionView/MainPage.xaml.cs create mode 100644 MauiStaggeredCollectionView/MauiProgram.cs create mode 100644 MauiStaggeredCollectionView/MauiStaggeredCollectionView.csproj create mode 100644 MauiStaggeredCollectionView/Platforms/Android/AndroidManifest.xml create mode 100644 MauiStaggeredCollectionView/Platforms/Android/MainActivity.cs create mode 100644 MauiStaggeredCollectionView/Platforms/Android/MainApplication.cs create mode 100644 MauiStaggeredCollectionView/Platforms/Android/Resources/values/colors.xml create mode 100644 MauiStaggeredCollectionView/Platforms/MacCatalyst/AppDelegate.cs create mode 100644 MauiStaggeredCollectionView/Platforms/MacCatalyst/Entitlements.plist create mode 100644 MauiStaggeredCollectionView/Platforms/MacCatalyst/Info.plist create mode 100644 MauiStaggeredCollectionView/Platforms/MacCatalyst/Program.cs create mode 100644 MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayout.cs create mode 100644 MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayoutFrameHolder.cs create mode 100644 MauiStaggeredCollectionView/Platforms/Tizen/Main.cs create mode 100644 MauiStaggeredCollectionView/Platforms/Tizen/tizen-manifest.xml create mode 100644 MauiStaggeredCollectionView/Platforms/Windows/App.xaml create mode 100644 MauiStaggeredCollectionView/Platforms/Windows/App.xaml.cs create mode 100644 MauiStaggeredCollectionView/Platforms/Windows/Package.appxmanifest create mode 100644 MauiStaggeredCollectionView/Platforms/Windows/app.manifest create mode 100644 MauiStaggeredCollectionView/Platforms/iOS/AppDelegate.cs create mode 100644 MauiStaggeredCollectionView/Platforms/iOS/Info.plist create mode 100644 MauiStaggeredCollectionView/Platforms/iOS/Program.cs create mode 100644 MauiStaggeredCollectionView/Platforms/iOS/StagLayout.cs create mode 100644 MauiStaggeredCollectionView/Platforms/iOS/StagLayoutFrameHolder.cs create mode 100644 MauiStaggeredCollectionView/Properties/launchSettings.json create mode 100644 MauiStaggeredCollectionView/README.mdpp create mode 100644 MauiStaggeredCollectionView/Resources/AppIcon/appicon.svg create mode 100644 MauiStaggeredCollectionView/Resources/AppIcon/appiconfg.svg create mode 100644 MauiStaggeredCollectionView/Resources/Images/dotnet_bot.png create mode 100644 MauiStaggeredCollectionView/Resources/Raw/AboutAssets.txt create mode 100644 MauiStaggeredCollectionView/Resources/Splash/splash.svg create mode 100644 MauiStaggeredCollectionView/Resources/Styles/Colors.xaml create mode 100644 MauiStaggeredCollectionView/Resources/Styles/Styles.xaml diff --git a/MauiSamples.sln b/MauiSamples.sln index 2dbc1b9f..4343e5b6 100644 --- a/MauiSamples.sln +++ b/MauiSamples.sln @@ -139,12 +139,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client.Android.UITests", "M EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "MauiTests\Client\Client.csproj", "{5411B28C-9E39-4FAF-BC6E-448C0DC9F0BC}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiStaggeredCollectionView", "MauiStaggeredCollectionView\MauiStaggeredCollectionView.csproj", "{7139BF92-182F-4CA9-B2A0-DAF4110A8C12}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7139BF92-182F-4CA9-B2A0-DAF4110A8C12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7139BF92-182F-4CA9-B2A0-DAF4110A8C12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7139BF92-182F-4CA9-B2A0-DAF4110A8C12}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {7139BF92-182F-4CA9-B2A0-DAF4110A8C12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7139BF92-182F-4CA9-B2A0-DAF4110A8C12}.Release|Any CPU.Build.0 = Release|Any CPU + {7139BF92-182F-4CA9-B2A0-DAF4110A8C12}.Release|Any CPU.Deploy.0 = Release|Any CPU {B91198E0-08DE-41B6-9056-95F90C3E0AD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B91198E0-08DE-41B6-9056-95F90C3E0AD8}.Debug|Any CPU.Build.0 = Debug|Any CPU {B91198E0-08DE-41B6-9056-95F90C3E0AD8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU diff --git a/MauiStaggeredCollectionView/App.xaml b/MauiStaggeredCollectionView/App.xaml new file mode 100644 index 00000000..ce1bbbb8 --- /dev/null +++ b/MauiStaggeredCollectionView/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/MauiStaggeredCollectionView/App.xaml.cs b/MauiStaggeredCollectionView/App.xaml.cs new file mode 100644 index 00000000..cc1c87df --- /dev/null +++ b/MauiStaggeredCollectionView/App.xaml.cs @@ -0,0 +1,11 @@ +namespace MauiStaggeredCollectionView; + +public partial class App : Application +{ + public App() + { + InitializeComponent(); + + MainPage = new AppShell(); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/AppShell.xaml b/MauiStaggeredCollectionView/AppShell.xaml new file mode 100644 index 00000000..d36d26d1 --- /dev/null +++ b/MauiStaggeredCollectionView/AppShell.xaml @@ -0,0 +1,15 @@ + + + + + + diff --git a/MauiStaggeredCollectionView/AppShell.xaml.cs b/MauiStaggeredCollectionView/AppShell.xaml.cs new file mode 100644 index 00000000..3e770ef9 --- /dev/null +++ b/MauiStaggeredCollectionView/AppShell.xaml.cs @@ -0,0 +1,9 @@ +namespace MauiStaggeredCollectionView; + +public partial class AppShell : Shell +{ + public AppShell() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/MainPage.xaml b/MauiStaggeredCollectionView/MainPage.xaml new file mode 100644 index 00000000..58f32748 --- /dev/null +++ b/MauiStaggeredCollectionView/MainPage.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + diff --git a/MauiStaggeredCollectionView/MainPage.xaml.cs b/MauiStaggeredCollectionView/MainPage.xaml.cs new file mode 100644 index 00000000..9c260e6d --- /dev/null +++ b/MauiStaggeredCollectionView/MainPage.xaml.cs @@ -0,0 +1,104 @@ +using System.Collections.ObjectModel; +using Microsoft.Maui.Controls.Handlers.Items; + +namespace MauiStaggeredCollectionView; + +public record Card(string Label, string Image); +public partial class MainPage : ContentPage +{ + public MainPage() + { + InitializeComponent(); + MyCollectionView.ItemsSource = new ObservableCollection() + { + new("Image 1","https://picsum.photos/200/200"), + new("Image 2", "https://picsum.photos/100/50"), + new("Image 3", "https://picsum.photos/100/200"), + new("Image 4", "https://picsum.photos/200/100"), + new("Image 5", "https://picsum.photos/150/100"), + new("Image 6", "https://picsum.photos/120/150"), + new("Image 7", "https://picsum.photos/180/140"), + new("Image 8", "https://picsum.photos/200/50"), + new("Image 9", "https://picsum.photos/50/150"), + new("Image 10", "https://picsum.photos/50/100"), + }; + } +} + +public class StaggeredStructuredItemsViewHandler : StructuredItemsViewHandler +{ + public StaggeredStructuredItemsViewHandler() : base(StaggeredStructuredItemsViewMapper) + { + + } + public StaggeredStructuredItemsViewHandler(PropertyMapper? mapper = null) : base(mapper ?? StaggeredStructuredItemsViewMapper) + { + + } + + public static PropertyMapper> StaggeredStructuredItemsViewMapper = new(StructuredItemsViewMapper) + { + [StructuredItemsView.ItemsLayoutProperty.PropertyName] = MapItemsLayout + }; + +#if ANDROID + private static void MapItemsLayout(StructuredItemsViewHandler handler, CollectionView view) + { + var platformView = handler.PlatformView as MauiRecyclerView, IItemsViewSource>; + switch (view.ItemsLayout) + { + case StaggeredItemsLayout staggeredItemsLayout: + platformView?.UpdateAdapter(); + platformView?.SetLayoutManager( + new AndroidX.RecyclerView.Widget.StaggeredGridLayoutManager( + staggeredItemsLayout.Span, + staggeredItemsLayout.Orientation == ItemsLayoutOrientation.Horizontal ? AndroidX.RecyclerView.Widget.StaggeredGridLayoutManager.Horizontal : AndroidX.RecyclerView.Widget.StaggeredGridLayoutManager.Vertical)); + break; + default: + platformView?.UpdateLayoutManager(); + break; + } + } +#endif + +#if IOS || MACCATALYST + protected override ItemsViewLayout SelectLayout() + { + var itemsLayout = ItemsView.ItemsLayout; + + if (itemsLayout is StaggeredItemsLayout staggeredItemsLayout) + { + return new StagLayout([(1d, 1d), (1d, 1d)], 0, staggeredItemsLayout, ItemSizingStrategy.MeasureAllItems); + } + + return base.SelectLayout(); + } +#endif + +#if WINDOWS + protected override Microsoft.UI.Xaml.Controls.ListViewBase SelectListViewBase() + { + return this.VirtualView.ItemsLayout switch + { + StaggeredItemsLayout staggeredItemsLayout => new Microsoft.UI.Xaml.Controls.GridView() { }, + _ => base.SelectListViewBase() + }; + } +#endif +} + +public class StaggeredItemsLayout(ItemsLayoutOrientation orientation) : ItemsLayout(orientation) +{ + public static readonly BindableProperty SpanProperty = BindableProperty.Create(nameof(Span), typeof(int), typeof(StaggeredItemsLayout), default(int)); + + public StaggeredItemsLayout() : this(ItemsLayoutOrientation.Vertical) + { + + } + + public int Span + { + get => (int)GetValue(SpanProperty); + set => SetValue(SpanProperty, value); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/MauiProgram.cs b/MauiStaggeredCollectionView/MauiProgram.cs new file mode 100644 index 00000000..54bee629 --- /dev/null +++ b/MauiStaggeredCollectionView/MauiProgram.cs @@ -0,0 +1,17 @@ +namespace MauiStaggeredCollectionView; + +public static class MauiProgram +{ + public static MauiApp CreateMauiApp() + { + var builder = MauiApp.CreateBuilder(); + builder + .UseMauiApp() + .ConfigureMauiHandlers(c => + { + c.AddHandler(); + }); + + return builder.Build(); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/MauiStaggeredCollectionView.csproj b/MauiStaggeredCollectionView/MauiStaggeredCollectionView.csproj new file mode 100644 index 00000000..3350ee71 --- /dev/null +++ b/MauiStaggeredCollectionView/MauiStaggeredCollectionView.csproj @@ -0,0 +1,31 @@ + + + + Exe + MauiStaggeredCollectionView + + + MauiStaggeredCollectionView + + + com.vladislavantonyuk.mauistaggeredcollectionview + + + 1.0 + 1 + + + + + + + + + + + + + + + + diff --git a/MauiStaggeredCollectionView/Platforms/Android/AndroidManifest.xml b/MauiStaggeredCollectionView/Platforms/Android/AndroidManifest.xml new file mode 100644 index 00000000..e9937ad7 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Android/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/Android/MainActivity.cs b/MauiStaggeredCollectionView/Platforms/Android/MainActivity.cs new file mode 100644 index 00000000..ffbb83e8 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Android/MainActivity.cs @@ -0,0 +1,13 @@ +using Android.App; +using Android.Content.PM; +using Android.OS; +using Android.Views; +using Android.Widget; +using AndroidX.RecyclerView.Widget; + +namespace MauiStaggeredCollectionView; + +[Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)] +public class MainActivity : MauiAppCompatActivity +{ +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/Android/MainApplication.cs b/MauiStaggeredCollectionView/Platforms/Android/MainApplication.cs new file mode 100644 index 00000000..091071be --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Android/MainApplication.cs @@ -0,0 +1,15 @@ +using Android.App; +using Android.Runtime; + +namespace MauiStaggeredCollectionView; + +[Application] +public class MainApplication : MauiApplication +{ + public MainApplication(IntPtr handle, JniHandleOwnership ownership) + : base(handle, ownership) + { + } + + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/Android/Resources/values/colors.xml b/MauiStaggeredCollectionView/Platforms/Android/Resources/values/colors.xml new file mode 100644 index 00000000..c04d7492 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Android/Resources/values/colors.xml @@ -0,0 +1,6 @@ + + + #512BD4 + #2B0B98 + #2B0B98 + \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/MacCatalyst/AppDelegate.cs b/MauiStaggeredCollectionView/Platforms/MacCatalyst/AppDelegate.cs new file mode 100644 index 00000000..4995d962 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/MacCatalyst/AppDelegate.cs @@ -0,0 +1,9 @@ +using Foundation; + +namespace MauiStaggeredCollectionView; + +[Register("AppDelegate")] +public class AppDelegate : MauiUIApplicationDelegate +{ + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/MacCatalyst/Entitlements.plist b/MauiStaggeredCollectionView/Platforms/MacCatalyst/Entitlements.plist new file mode 100644 index 00000000..de4adc94 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/MacCatalyst/Entitlements.plist @@ -0,0 +1,14 @@ + + + + + + + com.apple.security.app-sandbox + + + com.apple.security.network.client + + + + diff --git a/MauiStaggeredCollectionView/Platforms/MacCatalyst/Info.plist b/MauiStaggeredCollectionView/Platforms/MacCatalyst/Info.plist new file mode 100644 index 00000000..72689771 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/MacCatalyst/Info.plist @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + UIDeviceFamily + + 2 + + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/appicon.appiconset + + diff --git a/MauiStaggeredCollectionView/Platforms/MacCatalyst/Program.cs b/MauiStaggeredCollectionView/Platforms/MacCatalyst/Program.cs new file mode 100644 index 00000000..6f458463 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/MacCatalyst/Program.cs @@ -0,0 +1,15 @@ +using ObjCRuntime; +using UIKit; + +namespace MauiStaggeredCollectionView; + +public class Program +{ + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, typeof(AppDelegate)); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayout.cs b/MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayout.cs new file mode 100644 index 00000000..e785fb50 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayout.cs @@ -0,0 +1,54 @@ +using CoreGraphics; +using Foundation; +using System.Linq; +using Microsoft.Maui.Controls.Handlers.Items; +using UIKit; + +namespace MauiStaggeredCollectionView; + +public class StagLayout : ItemsViewLayout +{ + private float contentWidth; + + private StagLayoutFrameHolder frameHolder; + + public StagLayout(List<(double, double)> widthHeightRatios, float itemSpacing, ItemsLayout itemsLayout, ItemSizingStrategy sizingStrategy):base(itemsLayout, sizingStrategy) + { + frameHolder = new StagLayoutFrameHolder(widthHeightRatios, itemSpacing); + } + + public override CGSize CollectionViewContentSize => frameHolder.CollectionViewContentSize; + + public override void ConstrainTo(CGSize size) + { + + } + + public override void PrepareLayout() + { + base.PrepareLayout(); + + if (!frameHolder.Prepared || CollectionView.NumberOfSections() == 0) + { + return; + } + frameHolder.Prepare(CollectionView.NumberOfItemsInSection(0).ToInt32(), contentWidth); + } + + + public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect) + { + return frameHolder.LayoutAttributesForElements(rect); + } + + public override UICollectionViewLayoutAttributes LayoutAttributesForItem(NSIndexPath indexPath) + { + return frameHolder.LayoutAttributesForItem(indexPath); + } + + public override void InvalidateLayout() + { + base.InvalidateLayout(); + frameHolder.InvalidateLayout(); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayoutFrameHolder.cs b/MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayoutFrameHolder.cs new file mode 100644 index 00000000..daaefe61 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/MacCatalyst/StagLayoutFrameHolder.cs @@ -0,0 +1,128 @@ +using CoreGraphics; +using Foundation; +using UIKit; + +namespace MauiStaggeredCollectionView; + +public class StagLayoutFrameHolder +{ + private List cache = new List(); + + private readonly List<(double, double)> widthHeightRatios; + private double contentWidth; + private double contentHeight; + private readonly double itemSpacing; + + public bool Prepared => cache.Any(); + + public CGSize CollectionViewContentSize => new CGSize(contentWidth, contentHeight); + + public StagLayoutFrameHolder(List<(double, double)> widthHeightRatios, double itemSpacing) + { + this.widthHeightRatios = widthHeightRatios; + this.itemSpacing = itemSpacing; + } + + public void Prepare(int itemCount, double contentWidth) + { + this.contentWidth = contentWidth; + + double xOffset = 0; + double yOffset = 0; + CGRect? previousItemFrame = null; + int ratioIndex = 0; + + for (int index = 0; index < itemCount; index++) + { + if (ratioIndex >= widthHeightRatios.Count) + { + ratioIndex = 0; + } + + var ratios = widthHeightRatios[ratioIndex]; + if (ratios.Item1 < 0.0f || ratios.Item1 > 1.0f || ratios.Item2 < 0.0f) + { + throw new ArgumentOutOfRangeException("Width ratio should be in [0.0, 1.0], with height ratio being in [0.0, ∞)"); + } + + bool isFullWidth = ratios.Item1 == 1.0d; + double halfItemSpacing = itemSpacing * 0.5f; + (double width, double height) = ( + (contentWidth * ratios.Item1) - (isFullWidth ? 0 : halfItemSpacing), + contentWidth * ratios.Item2 + ); + + CGRect frame = new CGRect(xOffset, yOffset, width, height); + + var indexPath = NSIndexPath.Create(index, 0); + var attributes = UICollectionViewLayoutAttributes.CreateForCell(indexPath); + attributes.Frame = frame; + cache.Add(attributes); + + contentHeight = Math.Max(contentHeight, frame.Bottom); + + bool hasReachedEnd = xOffset + width >= contentWidth; + bool isItemNextToIt; + if (previousItemFrame.HasValue) + { + // check whether there's still room to place another item to the right of it + bool isThereSpaceNextToIt = frame.Bottom <= previousItemFrame.Value.Bottom; + // Make sure there's no item next to it + isItemNextToIt = !isFullWidth && (frame.Bottom - itemSpacing) <= previousItemFrame.Value.Bottom; + + // If there's an item next to it and no space, the next item should have an xOffset of 0 + // and height will auto correct to not include spacing so that it is perfectly aligned + if (!isThereSpaceNextToIt && isItemNextToIt) + { + frame = new CGRect(xOffset, yOffset, width, height - itemSpacing); + attributes.Frame = frame; + cache.RemoveAt(cache.Count - 1); + cache.Add(attributes); + } + } + else + { + isItemNextToIt = false; + } + + if (isFullWidth || hasReachedEnd || isItemNextToIt) + { + xOffset = 0; + } + else + { + xOffset += frame.Width + itemSpacing; + } + + if (isFullWidth) + { + yOffset = frame.Bottom + itemSpacing; + } + else + { + if (previousItemFrame.HasValue) + { + yOffset = Math.Min(frame.Bottom.Value, previousItemFrame.Value.Bottom.Value) + itemSpacing; + } + } + + previousItemFrame = frame; + ratioIndex++; + } + } + + public UICollectionViewLayoutAttributes[] LayoutAttributesForElements(CGRect rect) + { + return cache.Where(attributes => attributes.Frame.IntersectsWith(rect)).ToArray(); + } + + public UICollectionViewLayoutAttributes? LayoutAttributesForItem(NSIndexPath indexPath) + { + return cache.ElementAtOrDefault(indexPath.Item.ToInt32()); + } + + public void InvalidateLayout() + { + cache.Clear(); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/Tizen/Main.cs b/MauiStaggeredCollectionView/Platforms/Tizen/Main.cs new file mode 100644 index 00000000..f8eda550 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Tizen/Main.cs @@ -0,0 +1,17 @@ +using Microsoft.Maui; +using Microsoft.Maui.Hosting; +using System; + +namespace MauiStaggeredCollectionView +{ + internal class Program : MauiApplication + { + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + + static void Main(string[] args) + { + var app = new Program(); + app.Run(args); + } + } +} diff --git a/MauiStaggeredCollectionView/Platforms/Tizen/tizen-manifest.xml b/MauiStaggeredCollectionView/Platforms/Tizen/tizen-manifest.xml new file mode 100644 index 00000000..e7cd3c55 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Tizen/tizen-manifest.xml @@ -0,0 +1,15 @@ + + + + + + maui-appicon-placeholder + + + + + http://tizen.org/privilege/internet + + + + \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/Windows/App.xaml b/MauiStaggeredCollectionView/Platforms/Windows/App.xaml new file mode 100644 index 00000000..bce63e47 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Windows/App.xaml @@ -0,0 +1,8 @@ + + + diff --git a/MauiStaggeredCollectionView/Platforms/Windows/App.xaml.cs b/MauiStaggeredCollectionView/Platforms/Windows/App.xaml.cs new file mode 100644 index 00000000..ff1f5d6b --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Windows/App.xaml.cs @@ -0,0 +1,29 @@ + + +// To learn more about WinUI, the WinUI project structure, +// and more about our project templates, see: http://aka.ms/winui-project-info. + +namespace MauiStaggeredCollectionView.WinUI +{ + /// + /// Provides application-specific behavior to supplement the default Application class. + /// + public partial class App : MauiWinUIApplication + { + /// + /// Initializes the singleton application object. This is the first line of authored code + /// executed, and as such is the logical equivalent of main() or WinMain(). + /// + public App() + { + this.InitializeComponent(); + } + + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); + } + +} + +namespace CommunityToolkit.WinUI.UI.Controls +{ +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/Windows/Package.appxmanifest b/MauiStaggeredCollectionView/Platforms/Windows/Package.appxmanifest new file mode 100644 index 00000000..9209a4c0 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Windows/Package.appxmanifest @@ -0,0 +1,46 @@ + + + + + + + + + $placeholder$ + User Name + $placeholder$.png + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MauiStaggeredCollectionView/Platforms/Windows/app.manifest b/MauiStaggeredCollectionView/Platforms/Windows/app.manifest new file mode 100644 index 00000000..500168a3 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/Windows/app.manifest @@ -0,0 +1,15 @@ + + + + + + + + true/PM + PerMonitorV2, PerMonitor + + + diff --git a/MauiStaggeredCollectionView/Platforms/iOS/AppDelegate.cs b/MauiStaggeredCollectionView/Platforms/iOS/AppDelegate.cs new file mode 100644 index 00000000..add9b546 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/iOS/AppDelegate.cs @@ -0,0 +1,11 @@ +using Foundation; +using Microsoft.Maui.Controls; +using System.Runtime.Serialization; + +namespace MauiStaggeredCollectionView; + +[Register("AppDelegate")] +public class AppDelegate : MauiUIApplicationDelegate +{ + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/iOS/Info.plist b/MauiStaggeredCollectionView/Platforms/iOS/Info.plist new file mode 100644 index 00000000..0004a4fd --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/iOS/Info.plist @@ -0,0 +1,32 @@ + + + + + LSRequiresIPhoneOS + + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + arm64 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + XSAppIconAssets + Assets.xcassets/appicon.appiconset + + diff --git a/MauiStaggeredCollectionView/Platforms/iOS/Program.cs b/MauiStaggeredCollectionView/Platforms/iOS/Program.cs new file mode 100644 index 00000000..6f458463 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/iOS/Program.cs @@ -0,0 +1,15 @@ +using ObjCRuntime; +using UIKit; + +namespace MauiStaggeredCollectionView; + +public class Program +{ + // This is the main entry point of the application. + static void Main(string[] args) + { + // if you want to use a different Application Delegate class from "AppDelegate" + // you can specify it here. + UIApplication.Main(args, null, typeof(AppDelegate)); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/iOS/StagLayout.cs b/MauiStaggeredCollectionView/Platforms/iOS/StagLayout.cs new file mode 100644 index 00000000..e785fb50 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/iOS/StagLayout.cs @@ -0,0 +1,54 @@ +using CoreGraphics; +using Foundation; +using System.Linq; +using Microsoft.Maui.Controls.Handlers.Items; +using UIKit; + +namespace MauiStaggeredCollectionView; + +public class StagLayout : ItemsViewLayout +{ + private float contentWidth; + + private StagLayoutFrameHolder frameHolder; + + public StagLayout(List<(double, double)> widthHeightRatios, float itemSpacing, ItemsLayout itemsLayout, ItemSizingStrategy sizingStrategy):base(itemsLayout, sizingStrategy) + { + frameHolder = new StagLayoutFrameHolder(widthHeightRatios, itemSpacing); + } + + public override CGSize CollectionViewContentSize => frameHolder.CollectionViewContentSize; + + public override void ConstrainTo(CGSize size) + { + + } + + public override void PrepareLayout() + { + base.PrepareLayout(); + + if (!frameHolder.Prepared || CollectionView.NumberOfSections() == 0) + { + return; + } + frameHolder.Prepare(CollectionView.NumberOfItemsInSection(0).ToInt32(), contentWidth); + } + + + public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect(CGRect rect) + { + return frameHolder.LayoutAttributesForElements(rect); + } + + public override UICollectionViewLayoutAttributes LayoutAttributesForItem(NSIndexPath indexPath) + { + return frameHolder.LayoutAttributesForItem(indexPath); + } + + public override void InvalidateLayout() + { + base.InvalidateLayout(); + frameHolder.InvalidateLayout(); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Platforms/iOS/StagLayoutFrameHolder.cs b/MauiStaggeredCollectionView/Platforms/iOS/StagLayoutFrameHolder.cs new file mode 100644 index 00000000..daaefe61 --- /dev/null +++ b/MauiStaggeredCollectionView/Platforms/iOS/StagLayoutFrameHolder.cs @@ -0,0 +1,128 @@ +using CoreGraphics; +using Foundation; +using UIKit; + +namespace MauiStaggeredCollectionView; + +public class StagLayoutFrameHolder +{ + private List cache = new List(); + + private readonly List<(double, double)> widthHeightRatios; + private double contentWidth; + private double contentHeight; + private readonly double itemSpacing; + + public bool Prepared => cache.Any(); + + public CGSize CollectionViewContentSize => new CGSize(contentWidth, contentHeight); + + public StagLayoutFrameHolder(List<(double, double)> widthHeightRatios, double itemSpacing) + { + this.widthHeightRatios = widthHeightRatios; + this.itemSpacing = itemSpacing; + } + + public void Prepare(int itemCount, double contentWidth) + { + this.contentWidth = contentWidth; + + double xOffset = 0; + double yOffset = 0; + CGRect? previousItemFrame = null; + int ratioIndex = 0; + + for (int index = 0; index < itemCount; index++) + { + if (ratioIndex >= widthHeightRatios.Count) + { + ratioIndex = 0; + } + + var ratios = widthHeightRatios[ratioIndex]; + if (ratios.Item1 < 0.0f || ratios.Item1 > 1.0f || ratios.Item2 < 0.0f) + { + throw new ArgumentOutOfRangeException("Width ratio should be in [0.0, 1.0], with height ratio being in [0.0, ∞)"); + } + + bool isFullWidth = ratios.Item1 == 1.0d; + double halfItemSpacing = itemSpacing * 0.5f; + (double width, double height) = ( + (contentWidth * ratios.Item1) - (isFullWidth ? 0 : halfItemSpacing), + contentWidth * ratios.Item2 + ); + + CGRect frame = new CGRect(xOffset, yOffset, width, height); + + var indexPath = NSIndexPath.Create(index, 0); + var attributes = UICollectionViewLayoutAttributes.CreateForCell(indexPath); + attributes.Frame = frame; + cache.Add(attributes); + + contentHeight = Math.Max(contentHeight, frame.Bottom); + + bool hasReachedEnd = xOffset + width >= contentWidth; + bool isItemNextToIt; + if (previousItemFrame.HasValue) + { + // check whether there's still room to place another item to the right of it + bool isThereSpaceNextToIt = frame.Bottom <= previousItemFrame.Value.Bottom; + // Make sure there's no item next to it + isItemNextToIt = !isFullWidth && (frame.Bottom - itemSpacing) <= previousItemFrame.Value.Bottom; + + // If there's an item next to it and no space, the next item should have an xOffset of 0 + // and height will auto correct to not include spacing so that it is perfectly aligned + if (!isThereSpaceNextToIt && isItemNextToIt) + { + frame = new CGRect(xOffset, yOffset, width, height - itemSpacing); + attributes.Frame = frame; + cache.RemoveAt(cache.Count - 1); + cache.Add(attributes); + } + } + else + { + isItemNextToIt = false; + } + + if (isFullWidth || hasReachedEnd || isItemNextToIt) + { + xOffset = 0; + } + else + { + xOffset += frame.Width + itemSpacing; + } + + if (isFullWidth) + { + yOffset = frame.Bottom + itemSpacing; + } + else + { + if (previousItemFrame.HasValue) + { + yOffset = Math.Min(frame.Bottom.Value, previousItemFrame.Value.Bottom.Value) + itemSpacing; + } + } + + previousItemFrame = frame; + ratioIndex++; + } + } + + public UICollectionViewLayoutAttributes[] LayoutAttributesForElements(CGRect rect) + { + return cache.Where(attributes => attributes.Frame.IntersectsWith(rect)).ToArray(); + } + + public UICollectionViewLayoutAttributes? LayoutAttributesForItem(NSIndexPath indexPath) + { + return cache.ElementAtOrDefault(indexPath.Item.ToInt32()); + } + + public void InvalidateLayout() + { + cache.Clear(); + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Properties/launchSettings.json b/MauiStaggeredCollectionView/Properties/launchSettings.json new file mode 100644 index 00000000..edf8aadc --- /dev/null +++ b/MauiStaggeredCollectionView/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "Windows Machine": { + "commandName": "MsixPackage", + "nativeDebugging": false + } + } +} \ No newline at end of file diff --git a/MauiStaggeredCollectionView/README.mdpp b/MauiStaggeredCollectionView/README.mdpp new file mode 100644 index 00000000..46e6ad49 --- /dev/null +++ b/MauiStaggeredCollectionView/README.mdpp @@ -0,0 +1,11 @@ +# .NET MAUI Staggered CollectionView + +!INCLUDE "./md/header.mdpp" + +Article: https://vladislavantonyuk.github.io/articles/.NET-MAUI-CollectionView-with-Staggered-Layout + +## Images + +![Android](https://ik.imagekit.io/VladislavAntonyuk/vladislavantonyuk/articles/54/54.png) + +!INCLUDE "./md/footer.mdpp" \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Resources/AppIcon/appicon.svg b/MauiStaggeredCollectionView/Resources/AppIcon/appicon.svg new file mode 100644 index 00000000..9d63b651 --- /dev/null +++ b/MauiStaggeredCollectionView/Resources/AppIcon/appicon.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Resources/AppIcon/appiconfg.svg b/MauiStaggeredCollectionView/Resources/AppIcon/appiconfg.svg new file mode 100644 index 00000000..21dfb25f --- /dev/null +++ b/MauiStaggeredCollectionView/Resources/AppIcon/appiconfg.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Resources/Images/dotnet_bot.png b/MauiStaggeredCollectionView/Resources/Images/dotnet_bot.png new file mode 100644 index 0000000000000000000000000000000000000000..f93ce025a8aadac29138413514bef90c11d892d9 GIT binary patch literal 69811 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%0A7N@|Cy{eV1d|BD;UZbFy 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 literal 0 HcmV?d00001 diff --git a/MauiStaggeredCollectionView/Resources/Raw/AboutAssets.txt b/MauiStaggeredCollectionView/Resources/Raw/AboutAssets.txt new file mode 100644 index 00000000..15d62448 --- /dev/null +++ b/MauiStaggeredCollectionView/Resources/Raw/AboutAssets.txt @@ -0,0 +1,15 @@ +Any raw assets you want to be deployed with your application can be placed in +this directory (and child directories). Deployment of the asset to your application +is automatically handled by the following `MauiAsset` Build Action within your `.csproj`. + + + +These files will be deployed with you package and will be accessible using Essentials: + + async Task LoadMauiAsset() + { + using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt"); + using var reader = new StreamReader(stream); + + var contents = reader.ReadToEnd(); + } diff --git a/MauiStaggeredCollectionView/Resources/Splash/splash.svg b/MauiStaggeredCollectionView/Resources/Splash/splash.svg new file mode 100644 index 00000000..21dfb25f --- /dev/null +++ b/MauiStaggeredCollectionView/Resources/Splash/splash.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Resources/Styles/Colors.xaml b/MauiStaggeredCollectionView/Resources/Styles/Colors.xaml new file mode 100644 index 00000000..30307a5d --- /dev/null +++ b/MauiStaggeredCollectionView/Resources/Styles/Colors.xaml @@ -0,0 +1,45 @@ + + + + + + + #512BD4 + #ac99ea + #242424 + #DFD8F7 + #9880e5 + #2B0B98 + + White + Black + #D600AA + #190649 + #1f1f1f + + #E1E1E1 + #C8C8C8 + #ACACAC + #919191 + #6E6E6E + #404040 + #212121 + #141414 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MauiStaggeredCollectionView/Resources/Styles/Styles.xaml b/MauiStaggeredCollectionView/Resources/Styles/Styles.xaml new file mode 100644 index 00000000..e0d36bb7 --- /dev/null +++ b/MauiStaggeredCollectionView/Resources/Styles/Styles.xaml @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.mdpp b/README.mdpp index fec6638f..dfad368c 100644 --- a/README.mdpp +++ b/README.mdpp @@ -77,4 +77,6 @@ The development guide can be found at [SETUP.md](./SETUP.md). 1. [MauiTests](MauiTests) - Testing .NET MAUI application using Appium and xUnit. +1. [MauiStaggeredCollectionView](MauiStaggeredCollectionView) - Create a Staggered Layout for CollectionView in .NET MAUI. + !INCLUDE "md/footer.mdpp" diff --git a/SETUP.md b/SETUP.md index c317083b..1e22d41d 100644 --- a/SETUP.md +++ b/SETUP.md @@ -1,6 +1,6 @@ ## Build solution -1. Install .NET 7 +1. Install .NET 8 2. Install .NET MAUI Workloads ```pwsh dotnet workload install maui diff --git a/md/thankyou.mdpp b/md/thankyou.mdpp index 28433818..43ae3130 100644 --- a/md/thankyou.mdpp +++ b/md/thankyou.mdpp @@ -1,3 +1,3 @@ ## Thank You -Special thanks to my friends and sponsors: @PeterFucci, Gerald Versluis (jfversluis), @renatolopes, Glen Herman, Olexii, Brady, Yury Michurin, VToegel, Aleksander Rokic, Jeffrey Williams, TimKyn, Standa Mikes, Aaron Schaefer, AIvanHeerden, 7 M O X D, gbrewer, Ryan, @janhjordie, erossiniuk, David. \ No newline at end of file +Special thanks to my friends and sponsors: @PeterFucci, Gerald Versluis (jfversluis), @renatolopes, Glen Herman, Olexii, Brady, Yury Michurin, VToegel, Aleksander Rokic, Jeffrey Williams, TimKyn, Standa Mikes, Aaron Schaefer, AIvanHeerden, 7 M O X D, gbrewer, Ryan, @janhjordie, erossiniuk, David, Sab. \ No newline at end of file