【问题标题】:ColumnLayout in Xamarin.FormsXamarin.Forms 中的列布局
【发布时间】:2020-03-15 22:30:13
【问题描述】:

我想我在 FlexLayout 中发现了一个错误。我尝试嵌套 2 个 FlexLayout,其中外部的应该是列容器,内部的应该是行容器。但是页面保持空白。我已经提交了一份错误报告,该报告已被接受分类,但我的猜测是需要一些时间来解决这个问题。所以我想我必须自己解决这个问题。

这就是我想在一个名为 ColumnLayout 的类中解决的问题。我试图让文本从列流到下一列和下一列,等等。

The quick brown fox jumps over the lazy dog. --> The quick brown fox jumps over the lazy dog. --> etc.
The quick brown fox jumps over the lazy dog. |   The quick brown fox jumps over the lazy dog. |
The quick brown fox jumps over the lazy dog. |   The quick brown fox jumps over the lazy dog. |
The quick brown fox jumps over the lazy dog. |   The quick brown fox jumps over the lazy dog. |
The quick brown fox jumps over the lazy dog. |   The quick brown fox jumps over the lazy dog. |
The quick brown fox jumps over the lazy dog. |   The quick brown fox jumps over the lazy dog. |
The quick brown fox jumps over the lazy dog. |   The quick brown fox jumps over the lazy dog. |
----------------------------------------------   ----------------------------------------------

文本位于 StackLayouts 内,具有水平方向。这是一个印象。您可以在底部看到从页面流出的文本。这就是我想在第一个列的右侧开始新列的地方。

这是产生此输出的代码:

    private BindableObject GetXaml(Document doc)
    {
        var column = new ColumnLayout()
        {
            StyleClass = new List<string> { "ColumnContainer" }
        };

        foreach (var line in doc.Lines)
        {
            var row = new FlexLayout
            {
                StyleClass = new List<string> { "RowContainer" }
            };

            column.Children.Add(row);

            InterpretDirective(row, line);
        }

        return column;
    }

这是 ColumnLayout 类,目前只是 StackLayout:

using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;

namespace TGB.Xamarin.Forms.Layouts
{
    public class ColumnLayout : StackLayout
    {
        public ColumnLayout() { }

        protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
        {
            var size = base.OnMeasure(widthConstraint, heightConstraint);

            return size;
        }
    }
}

我不知道如何解决这个难题。 Xamarin 组件从外向内测量项目。似乎 OnMeasure(double widthConstraint, double heightConstraint) 以某种方式发挥了作用。有人可以向我解释这是如何工作的。

我的想法是在列的大小用尽时将垂直方向的堆栈布局添加到主水平堆栈布局中,但我不知道这是否是正确的策略。任何帮助表示赞赏。

**** 编辑 ****

这是另一个程序的示例:

【问题讨论】:

  • 我试图让文本从一列流到下一列和下一列,所以你想在 UI 中设置两列?从您的屏幕截图中,我不确定您的问题是什么,您能提供一张您想要做的屏幕截图吗?根据您的代码,您想在 UI 中显示文档吗?
  • 不,不完全是。查看“Quick brown fox...”行并向右滚动。它说'等'。因此,对于不适合当前列底部的任何行,列应该向右增长(添加了来自 GuitarTapp Pro 的屏幕截图)。
  • B.T.W. “文档”来自名为 Konves.ChordPro 的库。它将解析的 ChordPro 文本保存在对象树中。
  • 你能在这里发布更多代码吗?因为我不确定你想做什么?
  • 我想我找到了一个可以在这里工作的解决方案:docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/…

标签: xamarin.forms


【解决方案1】:

好的,经过一番摆弄,我已经开始工作了。关于 Xamarin.Forms 某些内容的文档很少,但我设法分析了应该如何完成。下面是 ColumnLayout 类的完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using Xamarin.Forms;

namespace TGB.Xamarin.Forms.Layouts
{
    public class ColumnLayout : Layout<View>
    {
        public static readonly BindableProperty ColumnSpacingProperty = BindableProperty.Create(
            "ColumnSpacing",
            typeof(double),
            typeof(ColumnLayout),
            5.0,
            propertyChanged: (bindable, oldvalue, newvalue) =>
            {
                ((ColumnLayout)bindable).InvalidateLayout();
            });

        public static readonly BindableProperty RowSpacingProperty = BindableProperty.Create(
            "RowSpacing",
            typeof(double),
            typeof(ColumnLayout),
            5.0,
            propertyChanged: (bindable, oldvalue, newvalue) =>
            {
                ((ColumnLayout)bindable).InvalidateLayout();
            });

        public double ColumnSpacing
        {
            set { SetValue(ColumnSpacingProperty, value); }
            get { return (double)GetValue(ColumnSpacingProperty); }
        }

        public double RowSpacing
        {
            set { SetValue(RowSpacingProperty, value); }
            get { return (double)GetValue(RowSpacingProperty); }
        }

        private (double totalHeight, double largestWidth) GetTotalChildSizes()
        {
            double totalHeight = 0;
            double largetsWidth = 0;

            foreach (var child in Children)
            {
                var request = child.Measure(double.PositiveInfinity, double.PositiveInfinity);
                largetsWidth = request.Request.Width > largetsWidth ? request.Request.Width : largetsWidth;
            }

            largetsWidth = largetsWidth > Application.Current.MainPage.Width ? Application.Current.MainPage.Width : largetsWidth;

            foreach (var child in Children)
            {
                var request = child.Measure(largetsWidth, double.PositiveInfinity);
                totalHeight += request.Request.Height;
            }

            return (totalHeight, largetsWidth);
        }

        protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
        {
            if (Children.Count(child => child.IsVisible) == 0)
            {
                return new SizeRequest();
            }

            var sizes = GetTotalChildSizes();

            var columns = 0;

            if (sizes.totalHeight < heightConstraint)
            {
                columns = 1;
            }
            else
            {
                columns = ((int)(sizes.totalHeight / heightConstraint)) + 1;
            }

            var requestedSize = new Size(columns * sizes.largestWidth, sizes.totalHeight) ;

            return new SizeRequest(requestedSize);
        }

        protected override void LayoutChildren(double x, double y, double width, double height)
        {
            double xChild = x;
            double yChild = y;
            double yNew = 0;

            var sizes = GetTotalChildSizes();

            foreach (View child in Children)
            {
                if (child.IsVisible)
                {
                    SizeRequest childSizeRequest = child.Measure(sizes.largestWidth, Double.PositiveInfinity);

                    if (yChild + childSizeRequest.Request.Height > height)
                    {
                        yChild = y;
                        yNew = y + RowSpacing + childSizeRequest.Request.Height;
                        xChild += ColumnSpacing + childSizeRequest.Request.Width;
                    }
                    else
                    {
                        yNew = yChild + RowSpacing + childSizeRequest.Request.Height;
                    }

                    LayoutChildIntoBoundingRegion(child, new Rectangle(new Point(xChild, yChild), childSizeRequest.Request));

                    yChild = yNew;
                }
            }
        }
    }
}

这是结果。

我还没有添加缓存,但我想我应该。 Measure() 例程经常被调用以获得正确的大小,因此一些缓存会真正加快速度。

【讨论】:

    猜你喜欢
    • 2020-05-19
    • 1970-01-01
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 2017-09-23
    • 2016-01-25
    • 2014-07-28
    相关资源
    最近更新 更多