Xamarin.Forms ListView size to content?

前端 未结 4 1831
星月不相逢
星月不相逢 2020-12-31 09:10

I have a pretty large form (adapted mainly for tablets), that has a TabbedPage nesting a ScrollView and a vertical StackPanel containi

相关标签:
4条回答
  • 2020-12-31 09:51

    Ok Assume your ListView is Populated with NewsFeeds, lets use an ObservableCollection to contain our data to populate a ListView as Below :

    XAML Code :

    <ListView x:Name="newslist"/>
    

    C# Code

    ObservableCollection <News> trends = new ObservableCollection<News>();
    

    Then you assign the trends List to the ListView :

    newslist.ItemSource = trends;
    

    Then , we have make some Logic on the ListView and the data , So that the ListView Wraps the data , as the data increases the ListView also increases and viceversa :

    int i = trends.Count;
    int heightRowList = 90;
    i = (i * heightRowList);
    newslist.HeightRequest = i;
    

    Therefore the complete code is :

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

    Hope it Helps .

    0 讨论(0)
  • 2020-12-31 09:58

    I could make a event handler that takes into account the on the changing size of the ListView cells. Here's it:

        <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 can be changed by Grid, StackLayout, etc. 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;
            }
        }
    

    When Frame is displaying (ListView.ItemTemplate is applying), size of frame changing. We take it's actual height via Measure() method and put it into Dictionary, which knows about current ListView and holds Frame's height. When last Frame is shown, we sum all heights. If there's no items, ListView_OnSizeChanged() sets listView.HeightRequest to 0.

    0 讨论(0)
  • 2020-12-31 09:59

    I may be grossly oversimplifying things here, but just adding HasUnevenRows="True" to the ListView worked for me.

    0 讨论(0)
  • 2020-12-31 10:00

    Based on Lutaaya's answer, I made a behavior that automates this, determining and setting the row-height (Gist).

    Behavior:

    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;
        }
      }
    }
    

    Usage:

    <ContentPage xmlns:xf="clr-namespace:Xamarin.Forms">
      <ListView>
        <ListView.Behaviors>
          <xf:AutoSizeBehavior />
    
    0 讨论(0)
提交回复
热议问题