How can I display elements in a ListView horizontally in Xamarin.forms xaml?

I am showing a list of SQLite objects in ListView, but I want them to be displayed horizontally. So instead:

| longitem        |
| item            |
| evenlongeritem  |
| item            |
| longeritem      |

I want it:

| longitem item   |
| evenlongeritem  |
| item longeritem |

It is important to note that the elements can have different widths, so just breaking the list into a certain number of columns will be an improvement, but not ideal. I also do not know the number of elements.

Here is the code that I have:

<ListView x:Name="inactiveList" VerticalOptions="Start" ItemTapped="PutBack">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextCell Text="{Binding Name}" TextColor="Black">
                  <TextCell.ContextActions>
                         <MenuItem Command="{Binding Source={x:Reference ListPage}, Path=DeleteListItem}" CommandParameter="{Binding .}" Text="delete" />
                  </TextCell.ContextActions>
              </TextCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Code for:

public ListPage()
{
    InitializeComponent();

    ObservableCollection<ListItem> activeItems =
        new ObservableCollection<ListItem>(
            App.ListItemRepo.GetActiveListItems());
    activeList.ItemsSource = activeItems;
    ...

I tried just wrap ViewCellin horizontal StackLayout, but I got this error:

Unhandled exception: System.InvalidCastException: The specified listing is not valid.

I'm not sure what this error means, but I don’t think it can be added StackLayoutinternally DataTemplate. I also can not make it ListViewhorizontal.

-

4:

, , , , ListView. ?

ListView.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns:local="clr-namespace:Myapp">
        <!-- ... -->
        <local:WrapLayout x:Name="inactiveList" ItemsSource="{Binding .}" Spacing="5" />

ListView.xaml.cs

using Myapp.Models;
using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using SQLite;
using System.Threading.Tasks;
using System.IO;
using Xamarin.Forms;
using System.Diagnostics;
using DLToolkit.Forms.Controls;

namespace Myapp
{
    public partial class ListPage
    {
        ...
        public ListPage()
        {
            InitializeComponent();

            ObservableCollection<ListItem> inactiveItems =
                new ObservableCollection<ListItem>(
                    App.ListItemRepo.GetInactiveListItems());
            inactiveList.ItemsSource = inactiveItems;
            inactiveList.HeightRequest = 50 * inactiveItems.Count;


        }
        ...
    }

    public class WrapLayout : Layout<View>
    {

        public ObservableCollection<ListItem> ItemsSource
        {
            get { return (ObservableCollection<ListItem>)GetValue(ItemSourceProperty); }
            set { SetValue(ItemSourceProperty, value); }
        }

        public static readonly BindableProperty ItemSourceProperty =
            BindableProperty.Create
            (
                "ItemsSource",
                typeof(ObservableCollection<ListItem>),
                typeof(WrapLayout),
                propertyChanged: (bindable, oldvalue, newvalue) => ((WrapLayout)bindable).AddViews()
            );


        void AddViews()
        {
            Children.Clear();
            foreach (ListItem s in ItemsSource)
            {
                Button button = new Button();
                button.BackgroundColor = Color.Red;
                button.Text = s.Name;
                button.TextColor = Color.Black;
                button.Clicked = "{Binding Source={x:Reference ListPage}, Path=PutBack}";
                Children.Add(button);
            }
        }

        public static readonly BindableProperty SpacingProperty =
            BindableProperty.Create
            (
                "Spacing",
                typeof(double),
                typeof(WrapLayout),
                10.0,
                propertyChanged: (bindable, oldvalue, newvalue) => ((WrapLayout)bindable).OnSizeChanged()
            );

        public double Spacing
        {
            get { return (double)GetValue(SpacingProperty); }
            set { SetValue(SpacingProperty, value); }
        }

        private void OnSizeChanged()
        {
            this.ForceLayout();
        }

        protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
        {
            if (WidthRequest > 0)
                widthConstraint = Math.Min(widthConstraint, WidthRequest);
            if (HeightRequest > 0)
                heightConstraint = Math.Min(heightConstraint, HeightRequest);

            double internalWidth = double.IsPositiveInfinity(widthConstraint) ? double.PositiveInfinity : Math.Max(0, widthConstraint);
            double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint);

            return DoHorizontalMeasure(internalWidth, internalHeight);
        }

        private SizeRequest DoHorizontalMeasure(double widthConstraint, double heightConstraint)
        {
            int rowCount = 1;

            double width = 0;
            double height = 0;
            double minWidth = 0;
            double minHeight = 0;
            double widthUsed = 0;

            foreach (var item in Children)
            {
                var size = item.Measure(widthConstraint, heightConstraint);

                height = Math.Max(height, size.Request.Height);

                var newWidth = width + size.Request.Width + Spacing;
                if (newWidth > widthConstraint)
                {
                    rowCount++;
                    widthUsed = Math.Max(width, widthUsed);
                    width = size.Request.Width;
                }
                else
                    width = newWidth;

                minHeight = Math.Max(minHeight, size.Minimum.Height);
                minWidth = Math.Max(minWidth, size.Minimum.Width);
            }

            if (rowCount > 1)
            {
                width = Math.Max(width, widthUsed);
                height = (height + Spacing) * rowCount - Spacing; // via MitchMilam 
            }

            return new SizeRequest(new Size(width, height), new Size(minWidth, minHeight));
        }

        protected override void LayoutChildren(double x, double y, double width, double height)
        {
            double rowHeight = 0;
            double yPos = y, xPos = x;

            foreach (var child in Children.Where(c => c.IsVisible))
            {
                var request = child.Measure(width, height);

                double childWidth = request.Request.Width;
                double childHeight = request.Request.Height;
                rowHeight = Math.Max(rowHeight, childHeight);

                if (xPos + childWidth > width)
                {
                    xPos = x;
                    yPos += rowHeight + Spacing;
                    rowHeight = 0;
                }

                var region = new Rectangle(xPos, yPos, childWidth, childHeight);
                LayoutChildIntoBoundingRegion(child, region);
                xPos += region.Width + Spacing;
            }
        }
    }
}
+6
3

My Post. .

Layout .

:

" local: WrapLayout xmlns clr-namespace: Myapp".

WrapLayout , ListPage.

,

BindableProperty ItemSource wraplayout subview .


Xmal

 <ContentPage.Content>
    <local:WrapLayout x:Name="wrap" ItemSource="{Binding .}" Spacing="5" />
</ContentPage.Content>

List<string> list = new List<string> {
            "11111111111111111111111",
            "22222",
            "333333333333333",
            "4",
            "55555555",
            "6666666666666666666666",
            "77777",
            "8888888888",
            "99999999999999999999999999999999"
};
this.BindingContext = list;

:

event WrapLayout, , . .

WrapLayout

namespace ImageWrapLayout
{
public class ButtonWithLongPressGesture : Button
{
    public EventHandler LongPressHandle;
    public EventHandler TapHandle;

    public void HandleLongPress(object sender, EventArgs e)
    {
        //Handle LongPressActivated Event
        LongPressHandle(sender, e);
    }

    public void HandleTap(object sender, EventArgs e)
    {
        //Handle Tap Event
        TapHandle(sender, e);
    }
}


public class WrapLayout : Layout<View>
{

    public List<string> ItemSource
    {
        get { return (List<string>)GetValue(ItemSourceProperty); }
        set { SetValue(ItemSourceProperty, value); }
    }

    public static readonly BindableProperty ItemSourceProperty =
        BindableProperty.Create
        (
            "ItemSource",
            typeof(List<string>),
            typeof(WrapLayout),
            propertyChanged: (bindable, oldvalue, newvalue) => ((WrapLayout)bindable).AddViews()
        );


    void AddViews()
    {
        Children.Clear();
        foreach (string s in ItemSource)
        {
            ButtonWithLongPressGesture button = new ButtonWithLongPressGesture();
            button.BackgroundColor = Color.Red;
            button.Text = s;
            button.TextColor = Color.Black;
            Children.Add(button);

            button.TapHandle += WrapLayoutTapHandle;
            button.LongPressHandle = WrapLayoutLongPressHandle;
        }
    }


    public EventHandler WrapLayoutLongPressHandle;
    public EventHandler WrapLayoutTapHandle;




    public static readonly BindableProperty SpacingProperty =
        BindableProperty.Create
        (
            "Spacing",
            typeof(double),
            typeof(WrapLayout),
            10.0,
            propertyChanged: (bindable, oldvalue, newvalue) => ((WrapLayout)bindable).OnSizeChanged()
        );

    public double Spacing
    {
        get { return (double)GetValue(SpacingProperty); }
        set { SetValue(SpacingProperty, value); }
    }

    private void OnSizeChanged()
    {
        this.ForceLayout();
    }

    protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
    {
        if (WidthRequest > 0)
            widthConstraint = Math.Min(widthConstraint, WidthRequest);
        if (HeightRequest > 0)
            heightConstraint = Math.Min(heightConstraint, HeightRequest);

        double internalWidth = double.IsPositiveInfinity(widthConstraint) ? double.PositiveInfinity : Math.Max(0, widthConstraint);
        double internalHeight = double.IsPositiveInfinity(heightConstraint) ? double.PositiveInfinity : Math.Max(0, heightConstraint);

        return DoHorizontalMeasure(internalWidth, internalHeight);
    }

    private SizeRequest DoHorizontalMeasure(double widthConstraint, double heightConstraint)
    {
        int rowCount = 1;

        double width = 0;
        double height = 0;
        double minWidth = 0;
        double minHeight = 0;
        double widthUsed = 0;

        foreach (var item in Children)
        {
            var size = item.Measure(widthConstraint, heightConstraint);

            height = Math.Max(height, size.Request.Height);

            var newWidth = width + size.Request.Width + Spacing;
            if (newWidth > widthConstraint)
            {
                rowCount++;
                widthUsed = Math.Max(width, widthUsed);
                width = size.Request.Width;
            }
            else
                width = newWidth;

            minHeight = Math.Max(minHeight, size.Minimum.Height);
            minWidth = Math.Max(minWidth, size.Minimum.Width);
        }

        if (rowCount > 1)
        {
            width = Math.Max(width, widthUsed);
            height = (height + Spacing) * rowCount - Spacing; // via MitchMilam 
        }

        return new SizeRequest(new Size(width, height), new Size(minWidth, minHeight));
    }

    protected override void LayoutChildren(double x, double y, double width, double height)
    {
        double rowHeight = 0;
        double yPos = y, xPos = x;

        foreach (var child in Children.Where(c => c.IsVisible))
        {
            var request = child.Measure(width, height);

            double childWidth = request.Request.Width;
            double childHeight = request.Request.Height;
            rowHeight = Math.Max(rowHeight, childHeight);

            if (xPos + childWidth > width)
            {
                xPos = x;
                yPos += rowHeight + Spacing;
                rowHeight = 0;
            }

            var region = new Rectangle(xPos, yPos, childWidth, childHeight);
            LayoutChildIntoBoundingRegion(child, region);
            xPos += region.Width + Spacing;
        }
    }
}
}

LongPress

[assembly: ExportRenderer(typeof(ButtonWithLongPressGesture), typeof(LongPressGestureRecognizerButtonRenderer))]
namespace ImageWrapLayout.iOS
{
class LongPressGestureRecognizerButtonRenderer : ButtonRenderer
{
    ButtonWithLongPressGesture view;

    public LongPressGestureRecognizerButtonRenderer()
    {
        this.AddGestureRecognizer(new UILongPressGestureRecognizer((longPress) => {
            if (longPress.State == UIGestureRecognizerState.Began)
            {
                view.HandleLongPress(view, new EventArgs());
            }
        }));
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
    {
        base.OnElementChanged(e);

        if (e.NewElement != null)
            view = e.NewElement as ButtonWithLongPressGesture;

        //if(Control == null)
        //{
        UIButton but = Control as UIButton;
            but.TouchUpInside += (sender, e1) => {
                view.HandleTap(view, new EventArgs());
            };
        //}
    }
}
}

(In Page.cs)

 inactiveList.WrapLayoutLongPressHandle += (sender, e) =>
 {
 };

 inactiveList.WrapLayoutTapHandle += (sender, e) =>
 {
 };
+6

. VisualElements BindableProperty, 270.

public static readonly BindableProperty RotationProperty;
public static readonly BindableProperty RotationXProperty;
public static readonly BindableProperty RotationYProperty;

This code is from the Visual Element class. Also see Sample below.

<ListView x:Name="MessagesListView" Rotation="270" ItemsSource="{Binding Items}" RowHeight="40">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <ViewCell.View>
          <StackLayout>
            <!--mylayouthere-->
          </StackLayout>
        </ViewCell.View>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>
+1
source

All Articles