9
votes

I'm trying to display a listview that contains some items and I just want to give a bit of space between those items.

I google about this but I could not find an answer that worked for me. Here is a solution that I found that has the same result that I wanted but didn't work: https://stackoverflow.com/a/30827419/1845593

I'm using xamarin forms 2.3.2.127 and I'd like to keep with xaml for this.

My xaml Code:

<pages:MainXaml.Content>
<ListView x:Name="AccountsList"
          ItemsSource="{Binding Items}"
          SeparatorVisibility="None"
          BackgroundColor="Gray">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <ViewCell.View>
          <StackLayout BackgroundColor="White" Margin="0,0,0,20" >
            <Label Text="{Binding Name}"
                 VerticalTextAlignment="Center"
                 LineBreakMode="TailTruncation"
                   />
            <Label Text="{Binding Amount}"
                   VerticalTextAlignment="Center"
                   LineBreakMode="TailTruncation"/>
          </StackLayout>
        </ViewCell.View>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>
</pages:MainXaml.Content>

I tried with spacing, Padding and Marging, none of them worked.

Visual Result/Expected:

enter image description here

Thanks

3

3 Answers

5
votes

I just find out that I need to set HasUnevenRows=True. Then I changed to Grid because I wanted a ">" at the end:

<ListView xmlns="http://xamarin.com/schemas/2014/forms"
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
          x:Class="ConsumerBanking.UserControls.AccountsListView"
          SeparatorVisibility="None"
          BackgroundColor="Transparent"
          HasUnevenRows="True" >

  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <ViewCell.View>

          <Grid BackgroundColor="White" Margin="0,0,0,1" >
            <Grid.RowDefinitions>
              <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="*" />
              <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>

            <StackLayout Grid.Column="0" Margin="10,5,0,5">
              <Label Text="{Binding Name}"
                     VerticalTextAlignment="Center"
                     LineBreakMode="TailTruncation"/>
              <Label Text="{Binding Amount}"
                     VerticalTextAlignment="Center"
                     LineBreakMode="TailTruncation"
                     FontSize="Large"/>
            </StackLayout>

            <Label Text=">" Grid.Column="1" VerticalTextAlignment="Center" Margin="0,0,20,0"
                   FontSize="Large" TextColor="{StaticResource darkGray}"/>
          </Grid>
        </ViewCell.View>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>
0
votes

Might also just use Margin="0,0,0,XSpaceBetweenRawsX" for any main container you choose to use inside the ViewCell. https://developer.xamarin.com/guides/xamarin-forms/user-interface/layouts/margin-and-padding/

0
votes

I recently wanted to implement the same appearance within a ListView. In my case, however, I needed to have swipe context actions for the items in the ListView. Using the approach described above, there was a size difference between the height of displayed items in the list vs the height of the context action menu.

The solution I came up with was to utilize grouping in the ListView with each group containing a single item and adding a custom group header view which was just a transparent view with the desired spacing height. This will ensure that the context menu size is equal to the item's view size.

Here is a simple class that I use to create and manage the grouping:

public class SingleItemGrouping<T>
{
    private ObservableCollection<SingleItemGroup<int, T>> _groups { get; set; } = new ObservableCollection<SingleItemGroup<int, T>>();
    public ObservableCollection<SingleItemGroup<int, T>> Groups { get { return _groups; } }

    private SingleItemGrouping(ObservableCollection<T> collection = null)
    {
        if (collection != null)
        {
            foreach (var item in collection)
            {
                this.Add(item);
            }
            collection.CollectionChanged += Collection_CollectionChanged;
        }
    }

    public static ObservableCollection<SingleItemGroup<int, T>> Create(ObservableCollection<T> collection)
    {
        SingleItemGrouping<T> ret = new SingleItemGrouping<T>(collection);
        return ret.Groups;
    }

    private void Collection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        var collection = sender as ObservableCollection<T>;
        if (e.OldItems != null)
        {
            foreach (var item in e.OldItems)
            {
                this.Remove((T)item);
            }
        }
        if (e.NewItems != null)
        {
            foreach (var item in e.NewItems)
            {
                if (collection != null)
                {
                    var index = collection.IndexOf((T)item);
                    if (index >= 0)
                    {
                        Insert(index, (T)item);
                        continue;
                    }
                }
                Add((T)item);
            }
        }
    }

    public void Insert(int index, T item)
    {
        int groupKey = item.GetHashCode();
        _groups.Insert(index, new SingleItemGroup<int, T>(groupKey, item));
    }

    public void Add(T item)
    {
        int groupKey = item.GetHashCode();
        _groups.Add(new SingleItemGroup<int, T>(groupKey, item));
    }

    public void Remove(T item)
    {
        int groupKey = item.GetHashCode();
        var remove = _groups.FirstOrDefault(x => x.GroupKey == groupKey);
        if (remove != null)
        {
            _groups.Remove(remove);
        }
    }

}

public class SingleItemGroup<K, TItem> : ObservableCollection<TItem>
{
    public K GroupKey { get; private set; }
    public TItem Item { get { return Items[0]; } }
    public SingleItemGroup(K key, TItem item)
    {
        GroupKey = key;
        Items.Add(item);
    }
}

And here is the implementation:

XAML:

       <ListView x:Name="listView"
                  HasUnevenRows="true"
                  SeparatorVisibility="None"
              IsGroupingEnabled="true">


            <ListView.GroupHeaderTemplate >
                <DataTemplate >
                    <ViewCell Height="20">
                        <Label />
                    </ViewCell>
                </DataTemplate>
            </ListView.GroupHeaderTemplate>

            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                       <ViewCell.ContextActions>    
                           <MenuItem Clicked="DeleteRecipe" CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" />    
                       </ViewCell.ContextActions>

                     <!-- define viewcell contents here -->
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
       </ListView.ItemTemplate>

.CS

        listView.ItemsSource = SingleItemGrouping<MyViewModel>.Create(myObservableCollection);