Xamarin.Forms ListView 大小到内容?
Xamarin.Forms ListView size to content?
我有一个相当大的表单(主要适用于平板电脑),它有一个 TabbedPage
嵌套 ScrollView
和一个包含许多控件的垂直 StackPanel
。
我很少会遇到 ListView
包含一些单行项目的情况,我需要根据内容调整大小。
我想摆脱它的滚动条,但无论如何我不希望它占用比其项目所需的更多 space。
有没有一种方法(即使是一种丑陋的方法)可以实现这一点而不必编写渲染器 x3 平台?
这是对我的树的伪描述:
<ContentPage>
<MasterDetailPage>
<MasterDetailPage.Detail>
<TabbedPage>
<ContentPage>
<ScrollView>
<StackPanel>
<!-- many controls-->
<ListView>
渲染时,ListView
之后有一个巨大的间隙。我怎样才能避免这种情况?
我试着摆弄 VerticalOptions
和 HeightRequest
,但没有一个有效。
我正在寻找一种动态方式(最好没有继承)来实现这一点,而不涉及自定义渲染器。
好的,假设您的 ListView 中填充了 NewsFeed,让我们使用 ObservableCollection
来包含我们的数据来填充 ListView,如下所示:
XAML代码:
<ListView x:Name="newslist"/>
C# 代码
ObservableCollection <News> trends = new ObservableCollection<News>();
然后将趋势列表分配给 ListView :
newslist.ItemSource = trends;
然后,我们在 ListView 和数据上做了一些逻辑,让 ListView 包装数据,随着数据的增加,ListView 也增加,反之亦然 :
int i = trends.Count;
int heightRowList = 90;
i = (i * heightRowList);
newslist.HeightRequest = i;
因此完整的代码是:
ObservableCollection <News> trends = new ObservableCollection<News>();
newslist.ItemSource = trends;
int i = trends.Count;
int heightRowList = 90;
i = (i * heightRowList);
newslist.HeightRequest = i;
希望对您有所帮助。
基于 Lutaaya 的 , I made a behavior that automates this, determining and setting the row-height (Gist).
行为:
namespace Xamarin.Forms
{
using System;
using System.Linq;
public class AutoSizeBehavior : Behavior<ListView>
{
ListView _ListView;
ITemplatedItemsView<Cell> Cells => _ListView;
protected override void OnAttachedTo(ListView bindable)
{
bindable.ItemAppearing += AppearanceChanged;
bindable.ItemDisappearing += AppearanceChanged;
_ListView = bindable;
}
protected override void OnDetachingFrom(ListView bindable)
{
bindable.ItemAppearing -= AppearanceChanged;
bindable.ItemDisappearing -= AppearanceChanged;
_ListView = null;
}
void AppearanceChanged(object sender, ItemVisibilityEventArgs e) =>
UpdateHeight(e.Item);
void UpdateHeight(object item)
{
if (_ListView.HasUnevenRows)
{
double height;
if ((height = _ListView.HeightRequest) ==
(double)VisualElement.HeightRequestProperty.DefaultValue)
height = 0;
height += MeasureRowHeight(item);
SetHeight(height);
}
else if (_ListView.RowHeight == (int)ListView.RowHeightProperty.DefaultValue)
{
var height = MeasureRowHeight(item);
_ListView.RowHeight = height;
SetHeight(height);
}
}
int MeasureRowHeight(object item)
{
var template = _ListView.ItemTemplate;
var cell = (Cell)template.CreateContent();
cell.BindingContext = item;
var height = cell.RenderHeight;
var mod = height % 1;
if (mod > 0)
height = height - mod + 1;
return (int)height;
}
void SetHeight(double height)
{
//TODO if header or footer is string etc.
if (_ListView.Header is VisualElement header)
height += header.Height;
if (_ListView.Footer is VisualElement footer)
height += footer.Height;
_ListView.HeightRequest = height;
}
}
}
用法:
<ContentPage xmlns:xf="clr-namespace:Xamarin.Forms">
<ListView>
<ListView.Behaviors>
<xf:AutoSizeBehavior />
我在这里可能过于简单化了,但仅将 HasUnevenRows="True"
添加到 ListView 对我有用。
我可以创建一个事件处理程序来考虑 ListView 单元格大小的变化。在这里:
<ListView ItemsSource="{Binding Items}"
VerticalOptions="Start"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
SelectionMode="None"
SizeChanged="ListView_OnSizeChanged">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<Frame Padding="10,0" SizeChanged="VisualElement_OnSizeChanged">
Frame可以通过Grid、StackLayout等来改变。
xaml.cs:
static readonly Dictionary<ListView, Dictionary<VisualElement, int>> _listViewHeightDictionary = new Dictionary<ListView, Dictionary<VisualElement, int>>();
private void VisualElement_OnSizeChanged(object sender, EventArgs e)
{
var frame = (VisualElement) sender;
var listView = (ListView)frame.Parent.Parent;
var height = (int) frame.Measure(1000, 1000, MeasureFlags.IncludeMargins).Minimum.Height;
if (!_listViewHeightDictionary.ContainsKey(listView))
{
_listViewHeightDictionary[listView] = new Dictionary<VisualElement, int>();
}
if (!_listViewHeightDictionary[listView].TryGetValue(frame, out var oldHeight) || oldHeight != height)
{
_listViewHeightDictionary[listView][frame] = height;
var fullHeight = _listViewHeightDictionary[listView].Values.Sum();
if ((int) listView.HeightRequest != fullHeight
&& listView.ItemsSource.Cast<object>().Count() == _listViewHeightDictionary[listView].Count
)
{
listView.HeightRequest = fullHeight;
listView.Layout(new Rectangle(listView.X, listView.Y, listView.Width, fullHeight));
}
}
}
private void ListView_OnSizeChanged(object sender, EventArgs e)
{
var listView = (ListView)sender;
if (listView.ItemsSource == null || listView.ItemsSource.Cast<object>().Count() == 0)
{
listView.HeightRequest = 0;
}
}
Frame 显示时(ListView.ItemTemplate 正在应用),frame 大小改变。
我们通过 Measure() 方法获取它的实际高度并将其放入 Dictionary,Dictionary 知道当前 ListView 并保存 Frame 的高度。当显示最后一帧时,我们将所有高度相加。
如果没有项目,ListView_OnSizeChanged() 将 listView.HeightRequest 设置为 0。
我知道这是一个旧线程,但到目前为止我找不到更好的解决方案 - 两年多后:-(
我正在使用 Xamarin.Forms v5.0.0.2244。
实施并应用了 Shimmy 在上面的“用法:”中建议的行为,但是,AppearanceChanged 是针对每个 listviewitem 执行的,而不是 listview 本身。因此,当在 UpdateHeight 中测量高度时,它测量单个项目的高度,并将列表视图的高度设置为该值——这是不正确的。
该行为似乎是合理的,因为它附加到 ItemAppearing 和 ItemDisappering 事件。
但是,根据 Shimmy 的想法,这里有一个改进的(但远非完美的)实现。这个想法是处理项目外观,测量这些项目并计算它们的总和,同时更新父列表视图高度。
对我来说,初始高度计算不正确,好像有些项目不会出现,因此没有被计算在内。
我希望有人可以改进它,或者指出更好的解决方案:
internal class ListViewAutoShrinkBehavior : Behavior<ListView>
{
ListView _listView;
double _height = 0;
protected override void OnAttachedTo(ListView listview)
{
listview.ItemAppearing += OnItemAppearing;
listview.ItemDisappearing += OnItemDisappearing;
_listView = listview;
}
protected override void OnDetachingFrom(ListView listview)
{
listview.ItemAppearing -= OnItemAppearing;
listview.ItemDisappearing -= OnItemDisappearing;
_listView = null;
}
void OnItemAppearing(object sender, ItemVisibilityEventArgs e)
{
_height += MeasureRowHeight(e.Item);
SetHeight(_height);
}
void OnItemDisappearing(object sender, ItemVisibilityEventArgs e)
{
_height -= MeasureRowHeight(e.Item);
SetHeight(_height);
}
int MeasureRowHeight(object item)
{
var template = _listView.ItemTemplate;
var cell = (Cell)template.CreateContent();
cell.BindingContext = item;
double height = cell.RenderHeight;
return (int)height;
}
void SetHeight(double height)
{
//TODO if header or footer is string etc.
if (_listView.Header is VisualElement header)
height += header.Height;
if (_listView.Footer is VisualElement footer)
height += footer.Height;
_listView.HeightRequest = height;
}
}
特别是当您的项目数量较少并且不需要滚动时,只需使用 bindableLayout。
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/bindable-layouts
这总是使它完全符合尺寸!
如果你有复杂的项目,有互动,那么这些工作非常好。
这里的大多数答案都有正确的想法,但似乎对 ViewCell
元素不太适用。这是我能想到的最有效的解决方案:
public class AutoSizeBehavior : Behavior<ListView>
{
ListView _listView;
VisualElement _parent;
ITemplatedItemsList<Cell> _itemsList;
Dictionary<int, double> _cells = new Dictionary<int, double>();
Dictionary<VisualElement, int> _elMap = new Dictionary<VisualElement, int>();
double _parentHeight;
double _contentHeight;
protected override void OnAttachedTo(ListView bindable)
{
bindable.ItemAppearing += HandleItemAppearing;
_listView = bindable;
_itemsList = ((ITemplatedItemsView<Cell>)_listView).TemplatedItems;
if (_listView.Parent is VisualElement parent)
{
AttachToParent(parent);
}
else
{
_listView.PropertyChanged += HandleListViewPropertyChanged;
}
for (int i = 0; i < _itemsList.Count; i++)
UpdateItemHeight(i);
}
protected override void OnDetachingFrom(ListView bindable)
{
_listView.ItemAppearing -= HandleItemAppearing;
_listView.PropertyChanged -= HandleListViewPropertyChanged;
for (int i = 0; i < _itemsList.Count; i++)
{
var cell = _itemsList[i];
cell.PropertyChanged -= HandleCellPropertyChanged;
}
foreach (var pair in _elMap)
{
var el = pair.Key;
el.SizeChanged -= HandleCellSizeChanged;
}
if (_parent != null)
_parent.SizeChanged -= HandleParentSizeChanged;
_elMap.Clear();
_cells.Clear();
_cells = null;
_itemsList = null;
_listView = null;
_parent = null;
_parentHeight = _contentHeight = -1;
}
#region Handlers
private void HandleItemAppearing(object sender, ItemVisibilityEventArgs e)
{
UpdateItemHeight(e.ItemIndex);
}
private void HandleListViewPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ListView.Parent))
{
if (_listView.Parent is VisualElement parent)
{
AttachToParent(parent);
_listView.PropertyChanged -= HandleListViewPropertyChanged;
}
}
}
private void HandleParentSizeChanged(object sender, EventArgs e)
{
if (_parent == null) return;
_parentHeight = _parent.Height;
AdjustListHeight();
}
private void HandleCellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!(sender is Cell cell)) return;
if (e.PropertyName == nameof(Cell.RenderHeight))
{
int index = _itemsList.IndexOf(cell);
if (index < 0)
return;
UpdateItemHeight(index);
}
}
private void HandleCellSizeChanged(object sender, EventArgs e)
{
if (!(sender is VisualElement el)) return;
if (_elMap.TryGetValue(el, out int index))
UpdateItemHeight(index);
}
#endregion
private void AttachToParent(VisualElement parent)
{
_parent = parent;
_parentHeight = _parent.Height;
_parent.SizeChanged += HandleParentSizeChanged;
}
private void UpdateItemHeight(int index)
{
Cell cell = _itemsList[index];
double newHeight;
if (!_cells.TryGetValue(index, out double oldHeight))
{
oldHeight = 0.0;
_cells[index] = oldHeight;
if (cell is ViewCell viewCell)
{
_elMap[viewCell.View] = index;
viewCell.View.SizeChanged += HandleCellSizeChanged;
}
else
{
cell.PropertyChanged += HandleCellPropertyChanged;
}
}
if (cell is ViewCell vCell)
{
newHeight = vCell.View.Height;
}
else
{
newHeight = cell.RenderHeight;
}
if (newHeight >= 0)
{
double delta = newHeight - oldHeight;
if (delta == 0) return;
_cells[index] = newHeight;
_contentHeight += delta;
AdjustListHeight();
}
}
private void AdjustListHeight()
{
if (_contentHeight > 0 && _contentHeight < _parentHeight)
{
_listView.HeightRequest = _contentHeight;
}
else if (_parentHeight >= 0)
{
if (_listView.HeightRequest != _parentHeight)
_listView.HeightRequest = _parentHeight;
}
}
}
AutoSizeBehavior
的这种实现可以很好地调整大小并自行清理。
我有一个相当大的表单(主要适用于平板电脑),它有一个 TabbedPage
嵌套 ScrollView
和一个包含许多控件的垂直 StackPanel
。
我很少会遇到 ListView
包含一些单行项目的情况,我需要根据内容调整大小。
我想摆脱它的滚动条,但无论如何我不希望它占用比其项目所需的更多 space。
有没有一种方法(即使是一种丑陋的方法)可以实现这一点而不必编写渲染器 x3 平台?
这是对我的树的伪描述:
<ContentPage>
<MasterDetailPage>
<MasterDetailPage.Detail>
<TabbedPage>
<ContentPage>
<ScrollView>
<StackPanel>
<!-- many controls-->
<ListView>
渲染时,ListView
之后有一个巨大的间隙。我怎样才能避免这种情况?
我试着摆弄 VerticalOptions
和 HeightRequest
,但没有一个有效。
我正在寻找一种动态方式(最好没有继承)来实现这一点,而不涉及自定义渲染器。
好的,假设您的 ListView 中填充了 NewsFeed,让我们使用 ObservableCollection
来包含我们的数据来填充 ListView,如下所示:
XAML代码:
<ListView x:Name="newslist"/>
C# 代码
ObservableCollection <News> trends = new ObservableCollection<News>();
然后将趋势列表分配给 ListView :
newslist.ItemSource = trends;
然后,我们在 ListView 和数据上做了一些逻辑,让 ListView 包装数据,随着数据的增加,ListView 也增加,反之亦然 :
int i = trends.Count;
int heightRowList = 90;
i = (i * heightRowList);
newslist.HeightRequest = i;
因此完整的代码是:
ObservableCollection <News> trends = new ObservableCollection<News>();
newslist.ItemSource = trends;
int i = trends.Count;
int heightRowList = 90;
i = (i * heightRowList);
newslist.HeightRequest = i;
希望对您有所帮助。
基于 Lutaaya 的
行为:
namespace Xamarin.Forms
{
using System;
using System.Linq;
public class AutoSizeBehavior : Behavior<ListView>
{
ListView _ListView;
ITemplatedItemsView<Cell> Cells => _ListView;
protected override void OnAttachedTo(ListView bindable)
{
bindable.ItemAppearing += AppearanceChanged;
bindable.ItemDisappearing += AppearanceChanged;
_ListView = bindable;
}
protected override void OnDetachingFrom(ListView bindable)
{
bindable.ItemAppearing -= AppearanceChanged;
bindable.ItemDisappearing -= AppearanceChanged;
_ListView = null;
}
void AppearanceChanged(object sender, ItemVisibilityEventArgs e) =>
UpdateHeight(e.Item);
void UpdateHeight(object item)
{
if (_ListView.HasUnevenRows)
{
double height;
if ((height = _ListView.HeightRequest) ==
(double)VisualElement.HeightRequestProperty.DefaultValue)
height = 0;
height += MeasureRowHeight(item);
SetHeight(height);
}
else if (_ListView.RowHeight == (int)ListView.RowHeightProperty.DefaultValue)
{
var height = MeasureRowHeight(item);
_ListView.RowHeight = height;
SetHeight(height);
}
}
int MeasureRowHeight(object item)
{
var template = _ListView.ItemTemplate;
var cell = (Cell)template.CreateContent();
cell.BindingContext = item;
var height = cell.RenderHeight;
var mod = height % 1;
if (mod > 0)
height = height - mod + 1;
return (int)height;
}
void SetHeight(double height)
{
//TODO if header or footer is string etc.
if (_ListView.Header is VisualElement header)
height += header.Height;
if (_ListView.Footer is VisualElement footer)
height += footer.Height;
_ListView.HeightRequest = height;
}
}
}
用法:
<ContentPage xmlns:xf="clr-namespace:Xamarin.Forms">
<ListView>
<ListView.Behaviors>
<xf:AutoSizeBehavior />
我在这里可能过于简单化了,但仅将 HasUnevenRows="True"
添加到 ListView 对我有用。
我可以创建一个事件处理程序来考虑 ListView 单元格大小的变化。在这里:
<ListView ItemsSource="{Binding Items}"
VerticalOptions="Start"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
SelectionMode="None"
SizeChanged="ListView_OnSizeChanged">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell >
<Frame Padding="10,0" SizeChanged="VisualElement_OnSizeChanged">
Frame可以通过Grid、StackLayout等来改变。 xaml.cs:
static readonly Dictionary<ListView, Dictionary<VisualElement, int>> _listViewHeightDictionary = new Dictionary<ListView, Dictionary<VisualElement, int>>();
private void VisualElement_OnSizeChanged(object sender, EventArgs e)
{
var frame = (VisualElement) sender;
var listView = (ListView)frame.Parent.Parent;
var height = (int) frame.Measure(1000, 1000, MeasureFlags.IncludeMargins).Minimum.Height;
if (!_listViewHeightDictionary.ContainsKey(listView))
{
_listViewHeightDictionary[listView] = new Dictionary<VisualElement, int>();
}
if (!_listViewHeightDictionary[listView].TryGetValue(frame, out var oldHeight) || oldHeight != height)
{
_listViewHeightDictionary[listView][frame] = height;
var fullHeight = _listViewHeightDictionary[listView].Values.Sum();
if ((int) listView.HeightRequest != fullHeight
&& listView.ItemsSource.Cast<object>().Count() == _listViewHeightDictionary[listView].Count
)
{
listView.HeightRequest = fullHeight;
listView.Layout(new Rectangle(listView.X, listView.Y, listView.Width, fullHeight));
}
}
}
private void ListView_OnSizeChanged(object sender, EventArgs e)
{
var listView = (ListView)sender;
if (listView.ItemsSource == null || listView.ItemsSource.Cast<object>().Count() == 0)
{
listView.HeightRequest = 0;
}
}
Frame 显示时(ListView.ItemTemplate 正在应用),frame 大小改变。 我们通过 Measure() 方法获取它的实际高度并将其放入 Dictionary,Dictionary 知道当前 ListView 并保存 Frame 的高度。当显示最后一帧时,我们将所有高度相加。 如果没有项目,ListView_OnSizeChanged() 将 listView.HeightRequest 设置为 0。
我知道这是一个旧线程,但到目前为止我找不到更好的解决方案 - 两年多后:-(
我正在使用 Xamarin.Forms v5.0.0.2244。 实施并应用了 Shimmy 在上面的“用法:”中建议的行为,但是,AppearanceChanged 是针对每个 listviewitem 执行的,而不是 listview 本身。因此,当在 UpdateHeight 中测量高度时,它测量单个项目的高度,并将列表视图的高度设置为该值——这是不正确的。 该行为似乎是合理的,因为它附加到 ItemAppearing 和 ItemDisappering 事件。
但是,根据 Shimmy 的想法,这里有一个改进的(但远非完美的)实现。这个想法是处理项目外观,测量这些项目并计算它们的总和,同时更新父列表视图高度。
对我来说,初始高度计算不正确,好像有些项目不会出现,因此没有被计算在内。 我希望有人可以改进它,或者指出更好的解决方案:
internal class ListViewAutoShrinkBehavior : Behavior<ListView>
{
ListView _listView;
double _height = 0;
protected override void OnAttachedTo(ListView listview)
{
listview.ItemAppearing += OnItemAppearing;
listview.ItemDisappearing += OnItemDisappearing;
_listView = listview;
}
protected override void OnDetachingFrom(ListView listview)
{
listview.ItemAppearing -= OnItemAppearing;
listview.ItemDisappearing -= OnItemDisappearing;
_listView = null;
}
void OnItemAppearing(object sender, ItemVisibilityEventArgs e)
{
_height += MeasureRowHeight(e.Item);
SetHeight(_height);
}
void OnItemDisappearing(object sender, ItemVisibilityEventArgs e)
{
_height -= MeasureRowHeight(e.Item);
SetHeight(_height);
}
int MeasureRowHeight(object item)
{
var template = _listView.ItemTemplate;
var cell = (Cell)template.CreateContent();
cell.BindingContext = item;
double height = cell.RenderHeight;
return (int)height;
}
void SetHeight(double height)
{
//TODO if header or footer is string etc.
if (_listView.Header is VisualElement header)
height += header.Height;
if (_listView.Footer is VisualElement footer)
height += footer.Height;
_listView.HeightRequest = height;
}
}
特别是当您的项目数量较少并且不需要滚动时,只需使用 bindableLayout。 https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/bindable-layouts 这总是使它完全符合尺寸! 如果你有复杂的项目,有互动,那么这些工作非常好。
这里的大多数答案都有正确的想法,但似乎对 ViewCell
元素不太适用。这是我能想到的最有效的解决方案:
public class AutoSizeBehavior : Behavior<ListView>
{
ListView _listView;
VisualElement _parent;
ITemplatedItemsList<Cell> _itemsList;
Dictionary<int, double> _cells = new Dictionary<int, double>();
Dictionary<VisualElement, int> _elMap = new Dictionary<VisualElement, int>();
double _parentHeight;
double _contentHeight;
protected override void OnAttachedTo(ListView bindable)
{
bindable.ItemAppearing += HandleItemAppearing;
_listView = bindable;
_itemsList = ((ITemplatedItemsView<Cell>)_listView).TemplatedItems;
if (_listView.Parent is VisualElement parent)
{
AttachToParent(parent);
}
else
{
_listView.PropertyChanged += HandleListViewPropertyChanged;
}
for (int i = 0; i < _itemsList.Count; i++)
UpdateItemHeight(i);
}
protected override void OnDetachingFrom(ListView bindable)
{
_listView.ItemAppearing -= HandleItemAppearing;
_listView.PropertyChanged -= HandleListViewPropertyChanged;
for (int i = 0; i < _itemsList.Count; i++)
{
var cell = _itemsList[i];
cell.PropertyChanged -= HandleCellPropertyChanged;
}
foreach (var pair in _elMap)
{
var el = pair.Key;
el.SizeChanged -= HandleCellSizeChanged;
}
if (_parent != null)
_parent.SizeChanged -= HandleParentSizeChanged;
_elMap.Clear();
_cells.Clear();
_cells = null;
_itemsList = null;
_listView = null;
_parent = null;
_parentHeight = _contentHeight = -1;
}
#region Handlers
private void HandleItemAppearing(object sender, ItemVisibilityEventArgs e)
{
UpdateItemHeight(e.ItemIndex);
}
private void HandleListViewPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ListView.Parent))
{
if (_listView.Parent is VisualElement parent)
{
AttachToParent(parent);
_listView.PropertyChanged -= HandleListViewPropertyChanged;
}
}
}
private void HandleParentSizeChanged(object sender, EventArgs e)
{
if (_parent == null) return;
_parentHeight = _parent.Height;
AdjustListHeight();
}
private void HandleCellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!(sender is Cell cell)) return;
if (e.PropertyName == nameof(Cell.RenderHeight))
{
int index = _itemsList.IndexOf(cell);
if (index < 0)
return;
UpdateItemHeight(index);
}
}
private void HandleCellSizeChanged(object sender, EventArgs e)
{
if (!(sender is VisualElement el)) return;
if (_elMap.TryGetValue(el, out int index))
UpdateItemHeight(index);
}
#endregion
private void AttachToParent(VisualElement parent)
{
_parent = parent;
_parentHeight = _parent.Height;
_parent.SizeChanged += HandleParentSizeChanged;
}
private void UpdateItemHeight(int index)
{
Cell cell = _itemsList[index];
double newHeight;
if (!_cells.TryGetValue(index, out double oldHeight))
{
oldHeight = 0.0;
_cells[index] = oldHeight;
if (cell is ViewCell viewCell)
{
_elMap[viewCell.View] = index;
viewCell.View.SizeChanged += HandleCellSizeChanged;
}
else
{
cell.PropertyChanged += HandleCellPropertyChanged;
}
}
if (cell is ViewCell vCell)
{
newHeight = vCell.View.Height;
}
else
{
newHeight = cell.RenderHeight;
}
if (newHeight >= 0)
{
double delta = newHeight - oldHeight;
if (delta == 0) return;
_cells[index] = newHeight;
_contentHeight += delta;
AdjustListHeight();
}
}
private void AdjustListHeight()
{
if (_contentHeight > 0 && _contentHeight < _parentHeight)
{
_listView.HeightRequest = _contentHeight;
}
else if (_parentHeight >= 0)
{
if (_listView.HeightRequest != _parentHeight)
_listView.HeightRequest = _parentHeight;
}
}
}
AutoSizeBehavior
的这种实现可以很好地调整大小并自行清理。