Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions samples/CommunityToolkit.Maui.Sample/AppShell.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
xmlns:behaviors="clr-namespace:CommunityToolkit.Maui.Sample.Pages.Behaviors"
xmlns:converters="clr-namespace:CommunityToolkit.Maui.Sample.Pages.Converters"
xmlns:extensions="clr-namespace:CommunityToolkit.Maui.Sample.Pages.Extensions"
xmlns:layouts="clr-namespace:CommunityToolkit.Maui.Sample.Pages.Layouts"
xmlns:pages="clr-namespace:CommunityToolkit.Maui.Sample.Pages"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="CommunityToolkit.Maui.Sample.AppShell">
Expand Down Expand Up @@ -52,6 +53,9 @@
<FlyoutItem Title="Extensions" Route="ExtensionsGalleryPage" Icon="dotnet_bot.png">
<ShellContent ContentTemplate="{DataTemplate extensions:ExtensionsGalleryPage}" />
</FlyoutItem>
<FlyoutItem Title="Layouts" Route="LayoutsGalleryPage" Icon="dotnet_bot.png">
<ShellContent ContentTemplate="{DataTemplate layouts:LayoutsGalleryPage}" />
</FlyoutItem>

<Shell.FlyoutFooter>
<Label Text="{Binding Source={x:Static sys:DateTime.Now}, StringFormat='{0:yyyy}'}"
Expand Down
7 changes: 6 additions & 1 deletion samples/CommunityToolkit.Maui.Sample/AppShell.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
using CommunityToolkit.Maui.Sample.Pages.Behaviors;
using CommunityToolkit.Maui.Sample.Pages.Converters;
using CommunityToolkit.Maui.Sample.Pages.Extensions;
using CommunityToolkit.Maui.Sample.Pages.Layouts;
using CommunityToolkit.Maui.Sample.ViewModels.Alerts;
using CommunityToolkit.Maui.Sample.ViewModels.Behaviors;
using CommunityToolkit.Maui.Sample.ViewModels.Converters;
using CommunityToolkit.Maui.Sample.ViewModels.Layouts;

namespace CommunityToolkit.Maui.Sample;

Expand Down Expand Up @@ -62,6 +64,9 @@ public partial class AppShell : Shell

// Add Extensions View Models
{ typeof(ColorAnimationExtensionsViewModel), (typeof(ExtensionsGalleryPage), typeof(ColorAnimationExtensionsPage)) },

// Add Layouts View Models
{ typeof(UniformItemsLayoutViewModel), (typeof(LayoutsGalleryPage), typeof(UniformItemsLayoutPage)) },
};

public AppShell()
Expand All @@ -88,7 +93,7 @@ public static string GetPageRoute(Type viewModelType)

static void RegisterRouting()
{
foreach(KeyValuePair<Type, (Type GalleryPageType, Type ContentPageType)> viewModelKeyValuePair in viewModelMappings)
foreach(var viewModelKeyValuePair in viewModelMappings)
{
Routing.RegisterRoute(GetPageRoute(viewModelKeyValuePair.Value.GalleryPageType, viewModelKeyValuePair.Value.ContentPageType), viewModelKeyValuePair.Value.ContentPageType);
}
Expand Down
5 changes: 5 additions & 0 deletions samples/CommunityToolkit.Maui.Sample/MauiProgram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using CommunityToolkit.Maui.Sample.ViewModels.Alerts;
using CommunityToolkit.Maui.Sample.ViewModels.Behaviors;
using CommunityToolkit.Maui.Sample.ViewModels.Converters;
using CommunityToolkit.Maui.Sample.ViewModels.Layouts;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]

Expand All @@ -19,6 +20,7 @@ public static MauiApp CreateMauiApp()
builder.Services.AddTransient<BehaviorsGalleryViewModel>();
builder.Services.AddTransient<ConvertersGalleryViewModel>();
builder.Services.AddTransient<ExtensionsGalleryViewModel>();
builder.Services.AddTransient<LayoutsGalleryViewModel>();
builder.Services.AddTransient<MainGalleryViewModel>();

// Add Behaviors View Models
Expand Down Expand Up @@ -48,6 +50,9 @@ public static MauiApp CreateMauiApp()
// Add Extensions
builder.Services.AddTransient<ColorAnimationExtensionsViewModel>();

// Add Layouts
builder.Services.AddTransient<UniformItemsLayoutViewModel>();

return builder.Build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using CommunityToolkit.Maui.Sample.ViewModels.Layouts;

namespace CommunityToolkit.Maui.Sample.Pages.Layouts;

public class LayoutsGalleryPage : BaseGalleryPage<LayoutsGalleryViewModel>
{
public LayoutsGalleryPage(LayoutsGalleryViewModel layoutGalleryViewModel) : base("Layouts", layoutGalleryViewModel)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BasePage
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:CommunityToolkit.Maui.Sample.Pages"
xmlns:mct="clr-namespace:CommunityToolkit.Maui.Layouts;assembly=CommunityToolkit.Maui"
xmlns:layouts="clr-namespace:CommunityToolkit.Maui.Sample.ViewModels.Layouts"
x:Class="CommunityToolkit.Maui.Sample.Pages.Layouts.UniformItemsLayoutPage"
x:TypeArguments="layouts:UniformItemsLayoutViewModel"
x:DataType="layouts:UniformItemsLayoutViewModel">

<ScrollView Padding="0">
<VerticalStackLayout Spacing="12" >
<Label Text="The UniformItemsLayout creates a grid where each Row and Column will have the same size"
Margin="0,0,0,12"/>

<Button Text="Add Color Box To Grids" Clicked="HandleAddButtonClicked" HorizontalOptions="Center" VerticalOptions="Center" Padding="8"/>

<Label Text="UniformItemsLayout with default settings"/>
<mct:UniformItemsLayout x:Name="UniformItemsLayout_Default">
<BoxView BackgroundColor="Black" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Green" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Purple" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Orange" HeightRequest="25" WidthRequest="25"/>
</mct:UniformItemsLayout>

<Label Text="UniformItemsLayout with MaxColumns=2 and MaxRows=2"/>
<mct:UniformItemsLayout x:Name="UniformItemsLayout_MaxRows2MaxColumns2" MaxColumns="2" MaxRows="2">
<BoxView BackgroundColor="Black" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Green" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Purple" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Orange" HeightRequest="25" WidthRequest="25"/>
</mct:UniformItemsLayout>

<Label Text="UniformItemsLayout with MaxRows=1"/>
<mct:UniformItemsLayout x:Name="UniformItemsLayout_MaxRows1" MaxRows="1">
<BoxView BackgroundColor="Black" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Green" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Purple" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Orange" HeightRequest="25" WidthRequest="25"/>
</mct:UniformItemsLayout>

<Label Text="UniformItemsLayout with MaxColumns=1"/>
<mct:UniformItemsLayout x:Name="UniformItemsLayout_MaxColumns1" MaxColumns="1">
<BoxView BackgroundColor="Black" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Green" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Purple" HeightRequest="25" WidthRequest="25"/>
<BoxView BackgroundColor="Orange" HeightRequest="25" WidthRequest="25"/>
</mct:UniformItemsLayout>
</VerticalStackLayout>
</ScrollView>
</pages:BasePage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Reflection;
using CommunityToolkit.Maui.Sample.ViewModels.Layouts;

namespace CommunityToolkit.Maui.Sample.Pages.Layouts;

public partial class UniformItemsLayoutPage : BasePage<UniformItemsLayoutViewModel>
{
readonly IReadOnlyList<Color> colors = typeof(Colors)
.GetFields(BindingFlags.Static | BindingFlags.Public)
.ToDictionary(c => c.Name, c => (Color)(c.GetValue(null) ?? throw new InvalidOperationException()))
.Values.ToList();

public UniformItemsLayoutPage(UniformItemsLayoutViewModel uniformItemsLayoutViewModel)
: base(uniformItemsLayoutViewModel)
{
InitializeComponent();
UniformItemsLayout_Default ??= new();
UniformItemsLayout_MaxColumns1 ??= new();
UniformItemsLayout_MaxRows1 ??= new();
UniformItemsLayout_MaxRows2MaxColumns2 ??= new();
}

void HandleAddButtonClicked(object? sender, System.EventArgs e)
{
const int widthRequest = 25;
const int heightRequest = 25;
var randomColor = colors[new Random().Next(colors.Count)];

UniformItemsLayout_Default.Children.Add(new BoxView
{
HeightRequest = widthRequest,
WidthRequest = heightRequest,
Color = randomColor
});

UniformItemsLayout_MaxRows1.Children.Add(new BoxView
{
HeightRequest = widthRequest,
WidthRequest = heightRequest,
Color = randomColor
});

UniformItemsLayout_MaxColumns1.Children.Add(new BoxView
{
HeightRequest = widthRequest,
WidthRequest = heightRequest,
Color = randomColor
});

var boxView = new BoxView
{
HeightRequest = widthRequest,
WidthRequest = heightRequest,
Color = randomColor
};

UniformItemsLayout_MaxRows2MaxColumns2.Children.Add(boxView);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using CommunityToolkit.Maui.Sample.Models;
using CommunityToolkit.Maui.Sample.Pages.Layouts;

namespace CommunityToolkit.Maui.Sample.ViewModels.Layouts;

public class LayoutsGalleryViewModel : BaseGalleryViewModel
{
public LayoutsGalleryViewModel()
: base(new []
{
SectionModel.Create<UniformItemsLayoutViewModel>(nameof(UniformItemsLayoutPage),
"A Grid where all rows and columns have the same size"),
})
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace CommunityToolkit.Maui.Sample.ViewModels.Layouts;

public class UniformItemsLayoutViewModel : BaseViewModel
{

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using CommunityToolkit.Maui.Sample.ViewModels.Alerts;
using CommunityToolkit.Maui.Sample.ViewModels.Behaviors;
using CommunityToolkit.Maui.Sample.ViewModels.Converters;
using CommunityToolkit.Maui.Sample.ViewModels.Layouts;

namespace CommunityToolkit.Maui.Sample.ViewModels;

Expand All @@ -21,6 +22,9 @@ public MainGalleryViewModel()

SectionModel.Create<ExtensionsGalleryViewModel>("Extensions", Color.FromArgb("#00EA56"),
"Extensions lets you add methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type."),

SectionModel.Create<LayoutsGalleryViewModel>("Layouts", Color.FromArgb("#00EA56"),
"Layouts"),
})
{
}
Expand Down
19 changes: 19 additions & 0 deletions src/CommunityToolkit.Maui.Core/Interfaces/IUniformItemsLayout.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Maui.Layouts;

namespace CommunityToolkit.Maui.Core.Interfaces;

/// <summary>
/// Uniform Items Layout Control
/// </summary>
public interface IUniformItemsLayout : ILayoutManager
{
/// <summary>
/// Max rows
/// </summary>
int MaxRows { get; }

/// <summary>
/// Max columns
/// </summary>
int MaxColumns { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using CommunityToolkit.Maui.Layouts;
using Xunit;

namespace CommunityToolkit.Maui.UnitTests.Views;

public class UniformItemsLayoutTests : BaseTest
{
const double childCount = 3;
const double childWidth = 20;
const double childHeight = 10;

readonly UniformItemsLayout uniformItemsLayout;
IView uniformChild;

public UniformItemsLayoutTests()
{
uniformChild = new TestView(childWidth, childHeight);

uniformItemsLayout = new UniformItemsLayout()
{
Children =
{
uniformChild,
uniformChild,
uniformChild
}
};
}

[Fact]
public void MeasureUniformItemsLayout_NoWrap()
{
var expectedSize = new Size(childWidth * childCount, childHeight);
var childSize = new Size(childWidth, childHeight);
uniformChild = new TestView(childSize);

var actualSize = uniformItemsLayout.Measure(childWidth * childCount, childHeight * childCount);

Assert.Equal(expectedSize, actualSize);
}

[Fact]
public void MeasureUniformItemsLayout_WrapOnNextRow()
{
var expectedSize = new Size(childWidth, childHeight * childCount);
var childSize = new Size(childWidth, childHeight);
uniformChild = new TestView(childSize);

var actualSize = uniformItemsLayout.Measure(childWidth, childHeight * childCount);

Assert.Equal(expectedSize, actualSize);
}

[Fact]
public void MaxRowsArrangeChildrenUniformItemsLayout()
{
var expectedSize = new Size(childWidth, childHeight);
uniformChild = new TestView(expectedSize);

uniformItemsLayout.MaxColumns = 1;
uniformItemsLayout.MaxRows = 1;

var actualSize = uniformItemsLayout.Measure(double.PositiveInfinity, double.PositiveInfinity);

Assert.Equal(expectedSize, actualSize);
}

[Fact]
public void ArrangeChildrenUniformItemsLayout()
{
var expectedSize = new Size(childWidth, childHeight);
uniformChild = new TestView(expectedSize);
uniformItemsLayout.Measure(double.PositiveInfinity, double.PositiveInfinity);

var actualSize = uniformItemsLayout.ArrangeChildren(new Rectangle(0, 0, childWidth * childCount, childHeight * childCount));

Assert.Equal(expectedSize, actualSize);
}

class TestView : View
{
readonly Size size;

public TestView(Size size)
{
this.size = size;
}

public TestView(double width, double height) : this(new Size(width, height))
{
}

protected override Size MeasureOverride(double widthConstraint, double heightConstraint)
{
return size;
}
}
}
Loading