Include headers/footers in EmptySource count so they show up when ItemsSource is null (#15979)
* Include headers/footers in EmptySource count so they show up when ItemsSource is null Fixes #8934 * More tests
This commit is contained in:
Родитель
05b741dba5
Коммит
b9f64e153d
|
@ -10,12 +10,12 @@ namespace Microsoft.Maui.Controls.Handlers.Items
|
||||||
{
|
{
|
||||||
public class EmptyViewAdapter : RecyclerView.Adapter
|
public class EmptyViewAdapter : RecyclerView.Adapter
|
||||||
{
|
{
|
||||||
int _headerHeight;
|
double _headerHeight;
|
||||||
int _headerViewType;
|
int _headerViewType;
|
||||||
object _headerView;
|
object _headerView;
|
||||||
DataTemplate _headerViewTemplate;
|
DataTemplate _headerViewTemplate;
|
||||||
|
|
||||||
int _footerHeight;
|
double _footerHeight;
|
||||||
int _footerViewType;
|
int _footerViewType;
|
||||||
object _footerView;
|
object _footerView;
|
||||||
DataTemplate _footerViewTemplate;
|
DataTemplate _footerViewTemplate;
|
||||||
|
@ -301,18 +301,25 @@ namespace Microsoft.Maui.Controls.Handlers.Items
|
||||||
if (item == null)
|
if (item == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var sizeRequest = new SizeRequest(new Size(0, 0));
|
var size = Size.Zero;
|
||||||
|
|
||||||
if (item is View view)
|
if (item is IView view)
|
||||||
sizeRequest = view.Measure(double.PositiveInfinity, double.PositiveInfinity, MeasureFlags.IncludeMargins);
|
{
|
||||||
|
if (view.Handler == null)
|
||||||
|
{
|
||||||
|
TemplateHelpers.GetHandler(view as View, ItemsView.FindMauiContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
size = view.Measure(double.PositiveInfinity, double.PositiveInfinity);
|
||||||
|
}
|
||||||
|
|
||||||
if (item is DataTemplate dataTemplate)
|
if (item is DataTemplate dataTemplate)
|
||||||
{
|
{
|
||||||
var content = dataTemplate.CreateContent() as View;
|
var content = dataTemplate.CreateContent() as IView;
|
||||||
sizeRequest = content.Measure(double.PositiveInfinity, double.PositiveInfinity, MeasureFlags.IncludeMargins);
|
size = content.Measure(double.PositiveInfinity, double.PositiveInfinity);
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemHeight = (int)sizeRequest.Request.Height;
|
var itemHeight = size.Height;
|
||||||
|
|
||||||
if (isHeader)
|
if (isHeader)
|
||||||
_headerHeight = itemHeight;
|
_headerHeight = itemHeight;
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace Microsoft.Maui.Controls.Handlers.Items
|
||||||
{
|
{
|
||||||
sealed internal class EmptySource : IItemsViewSource
|
sealed internal class EmptySource : IItemsViewSource
|
||||||
{
|
{
|
||||||
public int Count => 0;
|
public int Count => (HasHeader? 1 : 0) + (HasFooter? 1 : 0);
|
||||||
|
|
||||||
public bool HasHeader { get; set; }
|
public bool HasHeader { get; set; }
|
||||||
public bool HasFooter { get; set; }
|
public bool HasFooter { get; set; }
|
||||||
|
|
|
@ -50,5 +50,37 @@ namespace Microsoft.Maui.DeviceTests
|
||||||
// Without Exceptions here, the test has passed.
|
// Without Exceptions here, the test has passed.
|
||||||
Assert.Equal(0, (rootPage as IPageContainer<Page>).CurrentPage.Navigation.ModalStack.Count);
|
Assert.Equal(0, (rootPage as IPageContainer<Page>).CurrentPage.Navigation.ModalStack.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task NullItemsSourceDisplaysHeaderFooterAndEmptyView()
|
||||||
|
{
|
||||||
|
SetupBuilder();
|
||||||
|
|
||||||
|
var emptyView = new Label { Text = "Empty" };
|
||||||
|
var header = new Label { Text = "Header" };
|
||||||
|
var footer = new Label { Text = "Footer" };
|
||||||
|
|
||||||
|
var collectionView = new CollectionView
|
||||||
|
{
|
||||||
|
ItemsSource = null,
|
||||||
|
EmptyView = emptyView,
|
||||||
|
Header = header,
|
||||||
|
Footer = footer
|
||||||
|
};
|
||||||
|
|
||||||
|
ContentPage contentPage = new ContentPage() { Content = collectionView };
|
||||||
|
|
||||||
|
var frame = collectionView.Frame;
|
||||||
|
|
||||||
|
await CreateHandlerAndAddToWindow<IWindowHandler>(contentPage,
|
||||||
|
async (_) =>
|
||||||
|
{
|
||||||
|
await WaitForUIUpdate(frame, collectionView);
|
||||||
|
|
||||||
|
Assert.True(emptyView.Height > 0, "EmptyView should be laid out");
|
||||||
|
Assert.True(header.Height > 0, "Header should be laid out");
|
||||||
|
Assert.True(footer.Height > 0, "Footer should be laid out");
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -170,6 +170,66 @@ namespace Microsoft.Maui.DeviceTests
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(true, false, false)]
|
||||||
|
[InlineData(true, false, true)]
|
||||||
|
[InlineData(true, true, false)]
|
||||||
|
[InlineData(true, true, true)]
|
||||||
|
[InlineData(false, false, false)]
|
||||||
|
[InlineData(false, false, true)]
|
||||||
|
[InlineData(false, true, false)]
|
||||||
|
[InlineData(false, true, true)]
|
||||||
|
public async Task CollectionViewStructuralItems(bool hasHeader, bool hasFooter, bool hasData)
|
||||||
|
{
|
||||||
|
SetupBuilder();
|
||||||
|
|
||||||
|
double containerHeight = 500;
|
||||||
|
double containerWidth = 500;
|
||||||
|
var layout = new Grid() { IgnoreSafeArea = true, HeightRequest = containerHeight, WidthRequest = containerWidth };
|
||||||
|
|
||||||
|
Label headerLabel = hasHeader ? new Label { Text = "header" } : null;
|
||||||
|
Label footerLabel = hasFooter ? new Label { Text = "footer" } : null;
|
||||||
|
|
||||||
|
var collectionView = new CollectionView
|
||||||
|
{
|
||||||
|
ItemsLayout = LinearItemsLayout.Vertical,
|
||||||
|
ItemTemplate = new DataTemplate(() => new Label() { HeightRequest = 20, WidthRequest = 20 }),
|
||||||
|
Header = headerLabel,
|
||||||
|
Footer = footerLabel,
|
||||||
|
ItemsSource = hasData ? null : new ObservableCollection<string> { "data" }
|
||||||
|
};
|
||||||
|
|
||||||
|
layout.Add(collectionView);
|
||||||
|
|
||||||
|
var frame = collectionView.Frame;
|
||||||
|
|
||||||
|
await CreateHandlerAndAddToWindow<LayoutHandler>(layout, async handler =>
|
||||||
|
{
|
||||||
|
await WaitForUIUpdate(frame, collectionView);
|
||||||
|
frame = collectionView.Frame;
|
||||||
|
|
||||||
|
#if WINDOWS
|
||||||
|
// On Windows, the ListView pops in and changes the frame, then actually
|
||||||
|
// loads in the data, which updates it again. So we need to wait for the second
|
||||||
|
// update before checking the size
|
||||||
|
await WaitForUIUpdate(frame, collectionView);
|
||||||
|
frame = collectionView.Frame;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (hasHeader)
|
||||||
|
{
|
||||||
|
Assert.True(headerLabel.Height > 0);
|
||||||
|
Assert.True(headerLabel.Width > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasFooter)
|
||||||
|
{
|
||||||
|
Assert.True(footerLabel.Height > 0);
|
||||||
|
Assert.True(footerLabel.Width > 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static IEnumerable<object[]> GenerateLayoutOptionsCombos()
|
public static IEnumerable<object[]> GenerateLayoutOptionsCombos()
|
||||||
{
|
{
|
||||||
var layoutOptions = new LayoutOptions[] { LayoutOptions.Center, LayoutOptions.Start, LayoutOptions.End, LayoutOptions.Fill };
|
var layoutOptions = new LayoutOptions[] { LayoutOptions.Center, LayoutOptions.Start, LayoutOptions.End, LayoutOptions.Fill };
|
||||||
|
|
Загрузка…
Ссылка в новой задаче