0

ee

I need to create a header with multiselect options as you can see in the below image, the problem is i know how to create a multiselect list with grouping but i am not able get such options in horizontal layout and this options are dynamic as per the data passed they should get create and user can select and deselect this options on clicking can any one tell me what approach should i use or how can i achieve such functionality

Ronak Shetiya
  • 960
  • 6
  • 27

1 Answers1

1

Solution:

You can use listview + custom wraplayout to achieve your requirement.

I take the layout code from this thread:

Create new subclass which derives from Layout:

  1. Override OnMeasure to return the size of this layout .

  2. Override LayoutChildren to determine positions and sizes of the children.

  3. Create Bindable Properties to personalize the use on each need.

Custom Layout:

public class WrapLayout : Layout<View>
{
    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;
        }
    }
}

And in your xaml, use listView with layouted buttons in viewcell:

<ListView x:Name="EmployeeView" HasUnevenRows="True">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout>
                            <StackLayout BackgroundColor="LightBlue" Orientation="Horizontal">
                                <Label Text="qwewqe" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"></Label>
                                <Button Text="save" HorizontalOptions="EndAndExpand"></Button>
                            </StackLayout>
                            <StackLayout>
                                <local:WrapLayout Spacing="5">
                                <Button Text="   self   " BackgroundColor="Red"/>
                                <Button Text="   mother   " BackgroundColor="Green"/>
                                <Button Text="   father   " BackgroundColor="Gray"/>
                                <Button Text="   grandmother   " BackgroundColor="Blue"/>
                                <Button Text="   sister   " BackgroundColor="Orange"/>
                                <Button Text="   brother   " BackgroundColor="Aqua"/>
                                <Button Text="   self   " BackgroundColor="Yellow"/>
                                <Button Text="   grandfather   " BackgroundColor="Pink"/>
                                </local:WrapLayout>
                            </StackLayout>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

Remember to set the dataSource of listview and you can have a look at the result:

Screenshot

You could change the layout in my ViewCell to make it looks better. Try and let me if it meet your requirement?

nevermore
  • 15,432
  • 1
  • 12
  • 30