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
18 changes: 17 additions & 1 deletion src/Controls/src/Core/Handlers/Items/ItemsViewHandler.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,24 @@ void UpdateEmptyViewSize(double width, double height)

if (adapter is EmptyViewAdapter emptyViewAdapter)
{
var emptyView = emptyViewAdapter.EmptyView ?? emptyViewAdapter.EmptyViewTemplate;
Size size = Size.Zero;

IView view = emptyView as IView ?? (emptyView as DataTemplate)?.CreateContent() as IView;

if (view is not null)
{
if (view.Handler is null)
{
TemplateHelpers.GetHandler(view as View, this.MauiContext);
}

size = view.Measure(double.PositiveInfinity, double.PositiveInfinity);
}

var measuredHeight = !double.IsInfinity(size.Height) ? Context.ToPixels(size.Height) : height;
emptyViewAdapter.RecyclerViewWidth = width;
emptyViewAdapter.RecyclerViewHeight = height;
emptyViewAdapter.RecyclerViewHeight = measuredHeight > 0 ? measuredHeight : height;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,13 @@ protected virtual void RegisterViewTypes()

protected virtual CGRect DetermineEmptyViewFrame()
{
return new CGRect(CollectionView.Frame.X, CollectionView.Frame.Y,
CollectionView.Frame.Width, CollectionView.Frame.Height);
nfloat emptyViewHeight = 0;

if (_emptyViewFormsElement is IView emptyView)
{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vignesh-SF3580 this regressed when we don t have a layout as an empty view. I m created issue #26508 to track this. Do you have any ideas here? seems the height of a button is always 0 ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rmarinho , The issue occurs because the WrapperView for the button is being set during the rendering phase in the SetupContainer method. However, when the DetermineEmptyViewFrame method is called to measure the button, the SizeThatFitsWrapper logic is triggered. At this point, the WrapperView has no subviews, resulting in the default size (0, 0) being returned. This is due to the fact that the measurement depends on the subview hierarchy, which is not yet fully initialized during this phase.

The PR created by you PR #26513 effectively addresses this scenario.

emptyViewHeight = (nfloat)emptyView.Measure(CollectionView.Frame.Width, double.PositiveInfinity).Height;
}
return new CGRect(CollectionView.Frame.X, CollectionView.Frame.Y, CollectionView.Frame.Width, emptyViewHeight);
}

protected void RemeasureLayout(VisualElement formsElement)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,20 @@ protected override CGRect DetermineEmptyViewFrame()
nfloat headerHeight = 0;
var headerView = CollectionView.ViewWithTag(HeaderTag);

if (headerView != null)
if (headerView is not null)
headerHeight = headerView.Frame.Height;

nfloat footerHeight = 0;
var footerView = CollectionView.ViewWithTag(FooterTag);

if (footerView != null)
if (footerView is not null)
footerHeight = footerView.Frame.Height;

var emptyView = CollectionView.ViewWithTag(EmptyTag);

if (emptyView is not null)
return base.DetermineEmptyViewFrame();

return new CGRect(CollectionView.Frame.X, CollectionView.Frame.Y, CollectionView.Frame.Width,
Math.Abs(CollectionView.Frame.Height - (headerHeight + footerHeight)));
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue24966.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Maui.Controls.Sample.Issues.Issue24966"
xmlns:cv1="clr-namespace:Maui.Controls.Sample"
xmlns:local="clr-namespace:Maui.Controls.Sample.Issues"
x:Name="ThisMainPage"
Title="Main Page">

<Grid RowDefinitions="Auto,*">

<HorizontalStackLayout
Grid.Row="0"
Padding="20"
HorizontalOptions="Center"
Spacing="20">
<Button Command="{Binding AddCommand}" Text="Add item" AutomationId="AddButton" />
<Button Command="{Binding RemoveCommand}" Text="Remove item" AutomationId="RemoveButton" />
</HorizontalStackLayout>

<cv1:CollectionView1 Grid.Row="1" ItemsSource="{Binding ItemList}">

<cv1:CollectionView1.HeaderTemplate>
<DataTemplate>
<Label
Padding="10"
FontAttributes="Bold"
FontSize="Large"
Text="Cities" />
</DataTemplate>
</cv1:CollectionView1.HeaderTemplate>

<cv1:CollectionView1.ItemTemplate>
<DataTemplate>
<Label Padding="20,5,5,5" Text="{Binding .}" />
</DataTemplate>
</cv1:CollectionView1.ItemTemplate>

<cv1:CollectionView1.EmptyViewTemplate>
<DataTemplate>
<Label Padding="20,5,5,5" Text="Empty" />
</DataTemplate>
</cv1:CollectionView1.EmptyViewTemplate>

<cv1:CollectionView1.FooterTemplate>
<DataTemplate>
<Label
Padding="10"
FontAttributes="Bold"
FontSize="Large"
Text="Hello world !!!" />
</DataTemplate>
</cv1:CollectionView1.FooterTemplate>

</cv1:CollectionView1>

</Grid>
</ContentPage>
73 changes: 73 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue24966.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using System.Collections.Specialized;

namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 24966, "CollectionView, the footer moves to the bottom of the page when the empty view or empty view template is enabled")]
public partial class Issue24966
{
public Issue24966()
{
InitializeComponent();
BindingContext = new Issue24966ViewModel();
}
}
internal class Issue24966ViewModel
{
// Define a static list of cities to add to the collection
private List<string> _staticCities = new()
{
"Paris",
"New York",
"Tokyo",
"Berlin",
"Madrid",
"London"
};

private int _currentIndex = 0;

public ObservableCollection<string> ItemList { get; set; }

public ICommand AddCommand => new Command(Add);
public ICommand RemoveCommand => new Command(Remove);

public Issue24966ViewModel()
{
// Initialize the ItemList
ItemList = new ObservableCollection<string>();
}

private void Add()
{
// Add the next city from the static list
if (_currentIndex < _staticCities.Count)
{
ItemList.Add(_staticCities[_currentIndex]);
_currentIndex++;
}
else
{
// Optionally reset the index or handle the end of the list as needed
_currentIndex = 0; // Resetting to allow cycling through the list again
}
}

private void Remove()
{
// Remove the last item in the list if any exist
if (ItemList.Count > 0)
{
ItemList.RemoveAt(ItemList.Count - 1);
// Decrement the index to ensure the correct city is added next time
_currentIndex = Math.Max(0, _currentIndex - 1);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#if !MACCATALYST && !WINDOWS
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
internal class Issue24966 : _IssuesUITest
{
public Issue24966(TestDevice device) : base(device) { }

public override string Issue => "CollectionView, the footer moves to the bottom of the page when the empty view or empty view template is enabled";

[Test]
[Category(UITestCategories.CollectionView)]
public void CollectionViewFooterMovestoBottomWithEmptyvieworEmptyviewTemplate()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test is failing

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since updating to .NET 9 and enabling CollectionViewHandler2 in the iOS testing projects, we’re encountering UI test failures due to layout differences between CollectionViewHandler(with our custom fix in .NET 8) and CollectionViewHandler2. In the updated handler, the empty view is positioned incorrectly, overlapping the header, which alters the expected UI layout and causes screenshot comparison failures in tests.
The previous alignment fix for the empty view does not work with CollectionViewHandler2 due to differences in rendering flow. We are currently working on fixing this issue to ensure similar behavior to CollectionViewHandler for consistent UI rendering across versions.

A separate issue has been created to track progress: #25606,

{
App.WaitForElement("AddButton");
App.Tap("AddButton");
App.Tap("AddButton");
App.Tap("RemoveButton");
App.Tap("RemoveButton");
// Here we check for dynamic Emptyview and Footer proper proper alignment in view it should not be at the bottom of screen.
VerifyScreenshot();
}
}
}
#endif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.