There is more space than I need in ListView

前端 未结 5 1144
生来不讨喜
生来不讨喜 2021-01-19 19:56

I\'m using StackLayout and ListView to show some part of a view, but the ListView takes more space than I need, and leaves a blank space between the last row of the list and

相关标签:
5条回答
  • 2021-01-19 20:08

    As hvaughan3 said it's really not a good practice. But I had the same case and I used workaround with behavior:

    public class ListViewHeightBehavior : Behavior<ListView>
    {
        private ListView _listView;
    
        public static readonly BindableProperty ExtraSpaceProperty =
            BindableProperty.Create(nameof(ExtraSpace),
                                    typeof(double),
                                    typeof(ListViewHeightBehavior),
                                    0d);
    
        public double ExtraSpace
        {
            get { return (double)GetValue(ExtraSpaceProperty); }
            set { SetValue(ExtraSpaceProperty, value); }
        }
    
        protected override void OnAttachedTo(ListView bindable)
        {
            base.OnAttachedTo(bindable);
    
            _listView = bindable;
            _listView.PropertyChanged += (s, args) =>
            {
                var count = _listView.ItemsSource?.Count();
                if (args.PropertyName == nameof(_listView.ItemsSource)
                        && count.HasValue
                        && count.Value > 0)
                {
                    _listView.HeightRequest = _listView.RowHeight * count.Value + ExtraSpace;
                }
            };
        }
    }
    

    XAML:

         <ListView ItemsSource="{Binding Items}"
                   HasUnevenRows="True">
          <ListView.Behaviors>
            <behaviors:ListViewHeightBehavior ExtraSpace="180"/>
          </ListView.Behaviors>
          <ListView.ItemTemplate>
            <DataTemplate>
              <ViewCell>
                 // Your template
              </ViewCell>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
    
    0 讨论(0)
  • 2021-01-19 20:12

    First, Xamarin suggests not putting a ListView in a ScrollView, since they both offer scrolling and fight with each other. I have personally tried this and it can often cause weird behavior, especially on Android.

    Instead, what I do is use the ListView.Header with the ListView.HeaderTemplate and the ListView.Footer with the ListView.FooterTemplate. Xamarin link here This allows for your exact scenario but without the weird behavior issues. If you would like to see an example of that, let me know.

    If you must must must go with your current layout, you can try to check out this post talking about how the ListView needs to be sized with specific Height and Width or with LayoutOptions since it is not supposed to fit the size of it's contents. There are a couple solutions in that post, none that I have tried yet.

    In this post one of the workarounds that is given, says to add the the ListView to a StackLayout and add that to another StackLayout. Then set the inner StackLayout's VerticalOptions to LayoutOptions.FillAndExpand.

    So it might look like this:

    <ScrollView>
      <StackLayout Orientation="Vertical" Spacing="10">
    
        ....
    
        <StackLayout VerticalOptions="FillAndExpand">
          <ListView ItemsSource="{Binding Establishment.Contacts}" VerticalOptions="Start" HasUnevenRows="True">
            <ListView.ItemTemplate>
              <DataTemplate>
                <TextCell Text="{Binding Value}" Detail="{Binding StringType}" DetailColor="Gray"/>
              </DataTemplate>
            </ListView.ItemTemplate>
          </ListView>
        </StackLayout>
    
        ....
    
      </StackLayout>
    </ScrollView>
    
    0 讨论(0)
  • 2021-01-19 20:23

    Thank you guys, but nothing worked for me. The solution that I thought by myself surely isn't the best one, but it works for me.....

    At the XAML I left an empty StackLayout like this:

        <StackLayout x:Name="ContactsList" Orientation="Vertical" Spacing="10" Padding="8,0">
          <!-- Empty because it will be filled in code mode -->
        </StackLayout>
    

    And then, in the .cs file, I called this method after InitializeComponent() method:

        private void setUpContacts(Establishment establishment)
        {
            foreach(Contact contact in establishment.Contacts)
            {
                StackLayout row = new StackLayout
                {
                    Orientation = StackOrientation.Vertical
                };
    
                row.Children.Add(new Label
                {
                    TextColor = Color.Gray,
                    Text = string.Format("{0}:", contact.StringType)
                });
    
                row.Children.Add(new Label
                {
                    TextColor = Color.Black,
                    FontAttributes = FontAttributes.Bold,
                    Text = contact.Value,
                });
    
                row.GestureRecognizers.Add(new TapGestureRecognizer {
                    Command = new Command(() => OnContactTapped(row, contact))
                });
    
                ContactsList.Children.Add(row);
            }
        }
    

    I made this because the list isn't a really ListView, since I don't need scrolling functions directly in the list, it is just another part of the view. It won't cause any performance problem, I think, because it will have a small number of items (maximum 5). I'm marking this one as the correct answer to help others with this problem.

    Please, if this is a solution that does not work for others, let me know and I'll find another way to do this.

    0 讨论(0)
  • 2021-01-19 20:25

    I had issues with Yehor Hromadskyi's solution.

    • First off IEnumerable doesn't have a Count method. It must first be cast to an IEnumerable
    • Second, if you don't set RowHeight you then the whole list collapses and you have the opposite problem.

    Here are the changes to the code to fix those issues

    public class ListViewHeightBehavior : Behavior<ListView>
    {
        private ListView _listView;
    
        public static readonly BindableProperty ExtraSpaceProperty =
            BindableProperty.Create(nameof(ExtraSpace),
                                    typeof(double),
                                    typeof(ListViewHeightBehavior),
                                    0d);
    
        public static readonly BindableProperty DefaultRowHeightProperty =
            BindableProperty.Create(nameof(DefaultRowHeight),
                              typeof(int),
                              typeof(ListViewHeightBehavior),
                              40);
    
        public int DefaultRowHeight
        {
            get => (int)GetValue(DefaultRowHeightProperty);
            set => SetValue(DefaultRowHeightProperty, value);
        }
        public double ExtraSpace
        {
            get { return (double)GetValue(ExtraSpaceProperty); }
            set { SetValue(ExtraSpaceProperty, value); }
        }
    
        protected override void OnAttachedTo(ListView bindable)
        {
            base.OnAttachedTo(bindable);
    
            _listView = bindable;
            _listView.PropertyChanged += (s, args) =>
            {
                var count = _listView.ItemsSource?.Cast<object>()?.Count();
                if (args.PropertyName == nameof(_listView.ItemsSource)
                        && count.HasValue
                        && count.Value > 0)
                {
                    int rowHeight = _listView.RowHeight > 0 ? _listView.RowHeight : DefaultRowHeight;
                    _listView.HeightRequest = rowHeight * count.Value + ExtraSpace;
                }
            };
        }
    }
    
    0 讨论(0)
  • 2021-01-19 20:27

    Sample layout shows that, you are using ListView inside the ScrollView and ListView have child in different height (HasUnevenRows="True")

    <ScrollView>
         <ListView HasUnevenRows="True">
         </ListView>
    </ScrollView>
    

    This cause a blank space between the last row of the list and ScrollView.

    Since you are already added scroll view as root. You can use StackLayout (BindableLayout) for the same purpose.

    <ScrollView>
        <StackLayout
            x:Name="DummyList"
            BindableLayout.ItemsSource="{Binding ContactList}"
            Orientation="Vertical">
            <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <TextCell
                        Detail="{Binding StringType}"
                        DetailColor="Gray"
                        Text="{Binding Value}" />
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>
    </ScrollView>
    
    0 讨论(0)
提交回复
热议问题