Xamarin.Forms ListView大小到内容?

Shi*_*mmy 7 height listview sizetocontent xamarin.forms

我有一个非常大的形式(主要适用于平板电脑),有一个TabbedPage嵌套a ScrollView和一个StackPanel包含许多控件的垂直.

我很少出现一个ListView包含几个单行项目的地方,我需要它来确定内容的大小.
我想摆脱它的滚动条,但无论如何我不希望它占用比它的项目所需的空间更多的空间.
有没有办法(甚至是丑陋的)无需编写渲染器x3平台即可实现这一目标?

这是描述我的树的伪:

<ContentPage>
  <MasterDetailPage>
    <MasterDetailPage.Detail>
      <TabbedPage>
        <ContentPage>
          <ScrollView>
            <StackPanel>
              <!-- many controls-->
              <ListView>
Run Code Online (Sandbox Code Playgroud)

渲染后,有一个巨大的差距后ListView.我怎么能避免这种情况?

我试着搞乱了,VerticalOptions并且HeightRequest没有工作.

我正在寻找一种动态方式(最好没有继承)来实现这一点,而不涉及自定义渲染器.

Shi*_*mmy 9

根据Lutaaya的回答,我做了一个自动执行此操作的行为,确定并设置行高(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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

用法:

<ContentPage xmlns:xf="clr-namespace:Xamarin.Forms">
  <ListView>
    <ListView.Behaviors>
      <xf:AutoSizeBehavior />
Run Code Online (Sandbox Code Playgroud)

  • 如果每个单元格的行高是动态的,这将不起作用。对于动态单元格高度,您有什么方法可以做到这一点吗? (2认同)

Lut*_*ris 5

好的,假设您的 ListView 填充有 NewsFeeds,让我们使用一个ObservableCollection包含我们的数据来填充 ListView,如下所示:

XAML 代码:

<ListView x:Name="newslist"/>
Run Code Online (Sandbox Code Playgroud)

C# 代码

ObservableCollection <News> trends = new ObservableCollection<News>();
Run Code Online (Sandbox Code Playgroud)

然后将趋势列表分配给 ListView :

newslist.ItemSource = trends;
Run Code Online (Sandbox Code Playgroud)

然后,我们对ListView和数据做了一些Logic,让ListView包裹数据,随着数据的增加ListView也会增加,反之亦然

int i = trends.Count;
int heightRowList = 90;
i = (i * heightRowList);
newslist.HeightRequest = i;
Run Code Online (Sandbox Code Playgroud)

因此完整的代码是:

ObservableCollection <News> trends = new ObservableCollection<News>();
newslist.ItemSource = trends;
int i = trends.Count;
int heightRowList = 90;
i = (i * heightRowList);
newslist.HeightRequest = i;
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你 。