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

Commit

Permalink
Cache cell sizes after resize from estimates (#12919) fixes #10842 fixes
Browse files Browse the repository at this point in the history
 #10625

* Cache template sizes for use as estimated item sizes; fixes #10842

* Restore test items

* Add clarifying comments

* Cache cell measurements

* Correct caching index for Carousel

* Fix caching exception during item removal;
Fix empty view switching overlap;

* Update size when reusing Forms element on dequeued cell
  • Loading branch information
hartez committed Dec 29, 2020
1 parent 4ebb84b commit 5db7f40
Show file tree
Hide file tree
Showing 23 changed files with 783 additions and 38 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
@@ -1,4 +1,6 @@
namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
using Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.DataTemplateSelectorGalleries;

namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries
{
internal class DataTemplateGallery : ContentPage
{
Expand Down Expand Up @@ -26,6 +28,8 @@ public DataTemplateGallery()
new TemplateCodeCollectionViewGridGallery (ItemsLayoutOrientation.Horizontal), Navigation),
GalleryBuilder.NavButton("DataTemplateSelector", () =>
new DataTemplateSelectorGallery(), Navigation),
GalleryBuilder.NavButton("Varied Size Data Templates", () =>
new VariedSizeDataTemplateSelectorGallery(), Navigation),
}
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?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:datatemplateselectorgalleries="clr-namespace:Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.DataTemplateSelectorGalleries"
x:Class="Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.DataTemplateSelectorGalleries.VariedSizeDataTemplateSelectorGallery">

<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="MilkTemplate">
<Frame BorderColor="Red" BackgroundColor="Wheat" HeightRequest="100">
<StackLayout HeightRequest="100">
<Label Text="{Binding Name}" />
</StackLayout>
</Frame>
</DataTemplate>

<DataTemplate x:Key="CoffeeTemplate">
<Frame BorderColor="Red" BackgroundColor="SaddleBrown" HeightRequest="50">
<StackLayout HeightRequest="50">
<Label Text="{Binding Name}" />
</StackLayout>
</Frame>
</DataTemplate>

<DataTemplate x:Key="LatteTemplate" x:DataType="datatemplateselectorgalleries:Latte">
<Frame BorderColor="Red" BackgroundColor="BurlyWood" >
<StackLayout>
<Label Text="{Binding Name, StringFormat='Drink name is: {0}'}"/>
<Label Text=" The ingredients are: " Margin="0,10,0,0"/>
<StackLayout BindableLayout.ItemsSource="{Binding Ingredients}" >
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="datatemplateselectorgalleries:DrinkBase">
<Label Text="{Binding Name, StringFormat=' {0}'}" />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</Frame>
</DataTemplate>

<datatemplateselectorgalleries:DrinkTemplateSelector x:Key="VehicleTemplateSelector"
MilkTemplate="{StaticResource MilkTemplate}"
CoffeeTemplate="{StaticResource CoffeeTemplate}"
LatteTemplate="{StaticResource LatteTemplate}"/>
</ResourceDictionary>
</ContentPage.Resources>

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

<CollectionView ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource VehicleTemplateSelector}"
VerticalOptions="FillAndExpand"
ItemSizingStrategy="MeasureAllItems" />

<StackLayout Grid.Row="1">

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Text="Insert" Clicked="Insert_OnClicked"/>
<Button Grid.Column="1" Text="Add" Clicked="Add_OnClicked"/>
<Button Grid.Column="2" Text="Remove" Clicked="Remove_OnClicked"/>
</Grid>

<StackLayout Orientation="Horizontal">
<Label Text="Index"/>
<Entry Text="{Binding Index}" HorizontalOptions="FillAndExpand"/>
</StackLayout>

<Picker x:Name="TemplatePicker"
Title="Select a template"
TitleColor="Red"
SelectedItem="{Binding SelectedTemplate}">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Coffee</x:String>
<x:String>Milk</x:String>
<x:String>Latte</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>

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

namespace Xamarin.Forms.Controls.GalleryPages.CollectionViewGalleries.DataTemplateSelectorGalleries
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class VariedSizeDataTemplateSelectorGallery : ContentPage
{
string _index = "1";
string _itemsCount = "1";
int _counter = 6;
string _selectedTemplate = nameof(Latte);
bool _shouldTriggerReset;

public VariedSizeDataTemplateSelectorGallery()
{
InitializeComponent();
BindingContext = this;

foreach (var vehicle in CreateDefaultDrinks())
{
Items.Add(vehicle);
}

IEnumerable<DrinkBase> CreateDefaultDrinks()
{
yield return new Coffee("0");
yield return new Milk("1");
yield return new Coffee("2");
yield return new Coffee("3");
yield return new Milk("4");
yield return new Coffee("5");
}
}

public ObservableCollection<DrinkBase> Items { get; set; } =
new ObservableCollection<DrinkBase>();

public string Index
{
get => _index;
set => SetValue(ref _index, value);
}

public string ItemsCount
{
get => _itemsCount;
set => SetValue(ref _itemsCount, value);
}

public string SelectedTemplate
{
get => _selectedTemplate;
set => SetValue(ref _selectedTemplate, value);
}

public bool ShouldTriggerReset
{
get => _shouldTriggerReset;
set => SetValue(ref _shouldTriggerReset, value);
}

void Insert_OnClicked(object sender, EventArgs e)
{
if (!IsValid(out var index))
return;

Items.Insert(index, CreateDrink());
}

void Add_OnClicked(object sender, EventArgs e)
{
if (!IsValid(out var _))
return;

Items.Add(CreateDrink());
}

void SetValue<T>(ref T backingField, in T value, [CallerMemberName] string callerName = null)
{
if (Equals(backingField, value))
return;
OnPropertyChanging(callerName);
backingField = value;
OnPropertyChanged(callerName);
}

void Remove_OnClicked(object sender, EventArgs e)
{
if (!IsValid(out var index))
return;

Items.RemoveAt(index);
}

DrinkBase CreateDrink()
{
switch (SelectedTemplate)
{
case nameof(Milk):
return new Milk(_counter++.ToString());
case nameof(Coffee):
return new Coffee(_counter++.ToString());
case nameof(Latte):
{
var latte = new Latte(_counter++.ToString())
{
Ingredients = new ObservableCollection<DrinkBase>() { new Milk(_counter++.ToString()), new Coffee(_counter++.ToString()) }
};
return latte;
}
default:
throw new ArgumentException();
}
}

bool IsValid(out int index)
{
index = -1;
if (string.IsNullOrWhiteSpace(Index))
return false;
if (!int.TryParse(Index, out index))
return false;
if (index > Items.Count || index < 0)
return false;

return true;
}
}

class DrinkTemplateSelector : DataTemplateSelector
{
public DataTemplate CoffeeTemplate { get; set; }
public DataTemplate MilkTemplate { get; set; }
public DataTemplate LatteTemplate { get; set; }

protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
if (item is Coffee)
return CoffeeTemplate;

if (item is Milk)
return MilkTemplate;

if (item is Latte)
return LatteTemplate;

throw new ArgumentOutOfRangeException();
}
}

public abstract class DrinkBase
{
protected DrinkBase(string name) => Name = name;

public string Name { get; set; }

public override string ToString()
{
return Name;
}
}

class Coffee : DrinkBase
{
public Coffee(string name) : base(nameof(Coffee) + name) { }
}

class Milk : DrinkBase
{
public Milk(string name) : base(nameof(Milk) + name) { }
}

class Latte : DrinkBase
{
public Latte(string name) : base(nameof(Latte) + name) { }

public ObservableCollection<DrinkBase> Ingredients { get; set; } = new ObservableCollection<DrinkBase>();
}
}
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>
Loading

0 comments on commit 5db7f40

Please sign in to comment.