Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Cache cell measurements
Browse files Browse the repository at this point in the history
  • Loading branch information
hartez committed Dec 18, 2020
1 parent 322e710 commit 569458d
Show file tree
Hide file tree
Showing 13 changed files with 327 additions and 63 deletions.
4 changes: 0 additions & 4 deletions .Xamarin.Forms.iOS.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
"path": "Xamarin.Forms.sln",
"projects": [
"Stubs\\Xamarin.Forms.Platform.iOS\\Xamarin.Forms.Platform.iOS (Forwarders).csproj",
"XFCorePostProcessor.Tasks\\XFCorePostProcessor.Tasks.csproj",
"Xamarin.Flex\\Xamarin.Flex.shproj",
"Xamarin.Forms.Build.Tasks\\Xamarin.Forms.Build.Tasks.csproj",
"Xamarin.Forms.ControlGallery.iOS\\Xamarin.Forms.ControlGallery.iOS.csproj",
"Xamarin.Forms.Controls.Issues\\Xamarin.Forms.Controls.Issues.Shared\\Xamarin.Forms.Controls.Issues.Shared.shproj",
Expand All @@ -18,8 +16,6 @@
"Xamarin.Forms.Maps.iOS\\Xamarin.Forms.Maps.iOS.csproj",
"Xamarin.Forms.Maps\\Xamarin.Forms.Maps.csproj",
"Xamarin.Forms.Material.iOS\\Xamarin.Forms.Material.iOS.csproj",
"Xamarin.Forms.Pages.Azure\\Xamarin.Forms.Pages.Azure.csproj",
"Xamarin.Forms.Pages\\Xamarin.Forms.Pages.csproj",
"Xamarin.Forms.Platform.iOS.UnitTests\\Xamarin.Forms.Platform.iOS.UnitTests.csproj",
"Xamarin.Forms.Platform.iOS\\Xamarin.Forms.Platform.iOS.csproj",
"Xamarin.Forms.Platform\\Xamarin.Forms.Platform.csproj",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:chat="clr-namespace:Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.ItemSizeGalleries"
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.ItemSizeGalleries.ChatExample">

<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="Local">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="2*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Frame BorderColor="Green" BackgroundColor="LightGreen" CornerRadius="5" Grid.Column="1">
<StackLayout Margin="2">
<Label Text="{Binding Text}" LineBreakMode="WordWrap" FontSize="10" HorizontalTextAlignment="End" />
</StackLayout>
</Frame>
</Grid>
</DataTemplate>

<DataTemplate x:Key="Remote">
<Grid Padding="5,0,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Frame BorderColor="Blue" BackgroundColor="LightBlue" CornerRadius="5">
<StackLayout Margin="2">
<Label Text="{Binding Text}" LineBreakMode="WordWrap" FontSize="10" HorizontalTextAlignment="Start" />
</StackLayout>
</Frame>
</Grid>
</DataTemplate>

<chat:ChatTemplateSelector x:Key="ChatTemplateSelector"
LocalTemplate="{StaticResource Local}"
RemoteTemplate="{StaticResource Remote}"/>

</ResourceDictionary>
</ContentPage.Resources>

<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<StackLayout Orientation="Horizontal">
<Button x:Name="AppendRandomSizedItem" Text="Append Random Message" Margin="2" />
<Button x:Name="Clear" Text="Clear" Margin="2" />
<Button x:Name="Lots" Text="Add 1000 Messages" Margin="2" />
</StackLayout>

<CollectionView ItemsSource="{Binding ChatMessages}"
ItemTemplate="{StaticResource ChatTemplateSelector}"
ItemSizingStrategy="MeasureAllItems"
Grid.Row="1">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="5"/>
</CollectionView.ItemsLayout>
</CollectionView>

</Grid>
</ContentPage.Content>
</ContentPage>
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Xamarin.Forms.Xaml;

namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.ItemSizeGalleries
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ChatExample : ContentPage
{
Random _random = new Random(DateTime.Now.Millisecond);
ChatExampleViewModel _vm = new ChatExampleViewModel();

public ChatExample()
{
InitializeComponent();
BindingContext = _vm;

AppendRandomSizedItem.Clicked += AppendRandomChatMessage;
Clear.Clicked += ClearMessages;
Lots.Clicked += LotsOfMessages;
}

void AppendRandomChatMessage(object sender, EventArgs e)
{
_vm.ChatMessages.Add(GenerateRandomMessage());
}

void LotsOfMessages(object sender, EventArgs e)
{
var newVm = new ChatExampleViewModel(GenerateMessages(1000));
_vm = newVm;
BindingContext = _vm;
}

void ClearMessages(object sender, EventArgs e)
{
_vm.ChatMessages.Clear();
}

ChatMessage GenerateRandomMessage()
{
const string lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut "
+ "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip "
+ "ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat "
+ "nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";

var local = _random.Next(0, 2) == 1;

var textLength = _random.Next(0, lorem.Length - 1);

var text = lorem.Substring(0, textLength);

return new ChatMessage(text, local);
}

IEnumerable<ChatMessage> GenerateMessages(int count)
{
for (int n = 0; n < count; n++)
{
yield return GenerateRandomMessage();
}
}
}

public class ChatExampleViewModel
{
public ObservableCollection<ChatMessage> ChatMessages { get; }

public ChatExampleViewModel()
{
ChatMessages = new ObservableCollection<ChatMessage>();
}

public ChatExampleViewModel(IEnumerable<ChatMessage> chatMessages)
{
ChatMessages = new ObservableCollection<ChatMessage>(chatMessages);
}
}

public class ChatMessage
{
public bool IsLocal { get; set; }
public string Text { get; set; }

public ChatMessage(string text) : this(text, true) { }

public ChatMessage(string text, bool isLocal)
{
IsLocal = isLocal;
Text = text;
}
}

class ChatTemplateSelector : DataTemplateSelector
{
public DataTemplate LocalTemplate { get; set; }
public DataTemplate RemoteTemplate { get; set; }

protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item is ChatMessage message)
{
if (message.IsLocal)
{
return LocalTemplate;
}

return RemoteTemplate;
}

throw new ArgumentOutOfRangeException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ public ItemsSizeGallery()
GalleryBuilder.NavButton("Expanding Text (Horizontal List)", () =>
new DynamicItemSizeGallery(LinearItemsLayout.Horizontal), Navigation),
GalleryBuilder.NavButton("ItemSizing Strategy", () =>
new VariableSizeTemplateGridGallery (ItemsLayoutOrientation.Horizontal), Navigation)
new VariableSizeTemplateGridGallery (ItemsLayoutOrientation.Horizontal), Navigation),
GalleryBuilder.NavButton("Chat Example (Randomly Sized Items)", () =>
new ChatExample(), Navigation)
}
}
};
Expand Down
6 changes: 6 additions & 0 deletions Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
<EmbeddedResource Update="GalleryPages\CollectionViewGalleries\DataTemplateSelectorGalleries\VariedSizeDataTemplateSelectorGallery.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Update="GalleryPages\CollectionViewGalleries\ItemSizeGalleries\ChatExample.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Update="GalleryPages\DragAndDropGalleries\DragAndDropBetweenLayouts.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
Expand All @@ -88,6 +91,9 @@
<EmbeddedResource Update="GalleryPages\RadioButtonGalleries\RadioButtonGroupGalleryPage.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<Compile Update="GalleryPages\CollectionViewGalleries\ItemSizeGalleries\ChatExample.xaml.cs">
<DependentUpon>ChatExample.xaml</DependentUpon>
</Compile>
<Compile Update="GalleryPages\RadioButtonGalleries\RadioButtonGroupGallery.xaml.cs">
<DependentUpon>RadioButtonGroupGallery.xaml</DependentUpon>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using NUnit.Framework;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Foundation;
using NUnit.Framework;

namespace Xamarin.Forms.Platform.iOS.UnitTests
{
Expand Down Expand Up @@ -58,5 +61,26 @@ public void GenerateIndexPathRangeForLoop()
Assert.That((int)result[7].Item, Is.EqualTo(13));
Assert.That((int)result[8].Item, Is.EqualTo(14));
}

[Test]
public void IndexPathValidTest()
{
var list = new List<string>
{
"one",
"two",
"three"
};

var source = new ListSource(list);

var valid = NSIndexPath.FromItemSection(2, 0);
var invalidItem = NSIndexPath.FromItemSection(7, 0);
var invalidSection = NSIndexPath.FromItemSection(1, 9);

Assert.IsTrue(source.IsIndexPathValid(valid));
Assert.IsFalse(source.IsIndexPathValid(invalidItem));
Assert.IsFalse(source.IsIndexPathValid(invalidSection));
}
}
}
15 changes: 15 additions & 0 deletions Xamarin.Forms.Platform.iOS/CollectionView/IndexPathHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,20 @@ public static NSIndexPath[] GenerateLoopedIndexPathRange(int section, int sectio

return result;
}

public static bool IsIndexPathValid(this IItemsViewSource source, NSIndexPath indexPath)
{
if (indexPath.Section >= source.GroupCount)
{
return false;
}

if (indexPath.Item >= source.ItemCountInGroup(indexPath.Section))
{
return false;
}

return true;
}
}
}
Loading

0 comments on commit 569458d

Please sign in to comment.