How can I make buttons wrap around like in a tag cloud with Xamarin Forms?

后端 未结 3 913
温柔的废话
温柔的废话 2021-01-21 18:05

I have code like this:


   
      
      
3条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-21 19:07

    As Diego suggested , we can custom Layout to achieve the expect style.

    Create new subclass which derives from Layout , we just need to

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

    In Xmal

    
        

    Test

提交回复
热议问题