【问题标题】:AbsoluteLayout - Measure Label Height without placing label on UIAbsoluteLayout - 测量标签高度而不在 UI 上放置标签
【发布时间】:2022-01-25 01:32:37
【问题描述】:

我在 AbsoluteLayout 中手动定位标签。 要正确执行此操作,我想在将标签放置到 UI 之前知道标签高度。

我找到了这个解决方案,但并非没有实际放置标签:

public double MeasureLabelHeight(string text, double width, double fontSize, double lineHeight, string fontFamily)
    {
        Label label = new Label();
        label.WidthRequest = width;
        label.FontSize = fontSize;
        label.LineHeight = lineHeight;
        label.FontFamily = fontFamily;
        label.LineBreakMode = LineBreakMode.WordWrap;
        label.Text = text;
        MyAbsoluteLayout.Children.Add(view: label, position: new Point(0, Height)); //place out of sight
        var sizeRequest = label.Measure(widthConstraint: width, heightConstraint: double.MaxValue, flags: MeasureFlags.None);
        var labelTextHeight = sizeRequest.Request.Height;
        MyAbsoluteLayout.Children.Remove(label);
        return labelTextHeight;
    }

此解决方案适用于 UWP,我仍需在 Android 和 iOS 上进行测试。

不过,我想改进它。 如果没有将其实际放置在 AbsoluteLayout 中(看不见),我无法获得正确的高度值,并且有点担心这可能会导致额外重绘的开销。

我发现了一个old piece of code,它看似使用本机代码来执行此操作,但实际上并未将其放置在 iOS 和 Android 的 UI 中。我想知道是否有不需要平台特定代码的可用解决方案。

【问题讨论】:

    标签: xamarin.forms label measure absolutelayout


    【解决方案1】:

    让 Xamarin Forms 为您测量它们。然后将它们移动到位。

    通过继承 AbsoluteLayout 并添加一个页面可以设置的 Action 来实现这一点,以便在您的布局完成时调用 LayoutChildren

    MyAbsoluteLayout.cs:

    using System;
    using Xamarin.Forms;
    
    namespace XFSOAnswers
    {
        public class MyAbsoluteLayout : AbsoluteLayout
        {
            public MyAbsoluteLayout()
            {
            }
    
            // Containing page will set this, to act on children during LayoutChildren.
            public Action CustomLayoutAction { get; set; }
    
            private bool _busy;
    
            protected override void LayoutChildren(double x, double y, double width, double height)
            {
                // Avoid recursed layout calls as CustomLayoutAction moves children.
                if (_busy)
                    return;
    
                // Xamarin measures the children.
                base.LayoutChildren(x, y, width, height);
    
                _busy = true;
                try
                {
                    CustomLayoutAction?.Invoke();
                }
                finally
                {
                    _busy = false;
                    // Layout again, to position the children, based on adjusted (x,y)s.
                    base.LayoutChildren(x, y, width, height);
                }
            }
        }
    }
    

    示例用法 - MyAbsoluteLayoutPage.xaml:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:XFSOAnswers"
                 x:Class="XFSOAnswers.MyAbsoluteLayoutPage">
        <ContentPage.Content>
            <local:MyAbsoluteLayout x:Name="TheLayout">
                <!-- Layout positions start (0,0). Adjusted later in PositionLabels. -->
                <Label x:Name="Label1" Text="Welcome" />
                <Label x:Name="Label2" Text="to" />
                <Label x:Name="Label3" Text="Xamarin" />
                <Label x:Name="Label4" Text=".Forms!" />
            </local:MyAbsoluteLayout>
        </ContentPage.Content>
    </ContentPage>
    

    MyAbsoluteLayoutPage.xaml.cs:

    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    
    namespace XFSOAnswers
    {
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class MyAbsoluteLayoutPage : ContentPage
        {
            public MyAbsoluteLayoutPage()
            {
                InitializeComponent();
    
                TheLayout.CustomLayoutAction = PositionLabels;
            }
    
            private void PositionLabels()
            {
                // Optional: Set breakpoint after these, to check that the bounds have values.
                var bounds1 = Label1.Bounds;
                var bounds2 = Label2.Bounds;
                var bounds3 = Label3.Bounds;
                var bounds4 = Label4.Bounds;
    
                double x = 10;
                double y = 20;
                MoveAbsoluteChildTo(Label1, x, y);
                x += Label1.Width;
                y += Label1.Height;
    
                MoveAbsoluteChildTo(Label2, x, y);
                x += Label2.Width;
                y += Label2.Height;
    
                MoveAbsoluteChildTo(Label3, x, y);
                x += Label3.Width;
                y += Label3.Height;
    
                MoveAbsoluteChildTo(Label4, x, y);
            }
    
            private static void MoveAbsoluteChildTo(View child, double x, double y)
            {
                AbsoluteLayout.SetLayoutBounds(child, new Rect(x, y, child.Width, child.Height));
            }
        }
    }
    

    结果:


    参见ToolmakerSteve - repo XFormsSOAnswers 中的MyAbsoluteLayoutMyAbsoluteLayoutPage

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-23
      • 2011-06-12
      • 2021-10-25
      • 2014-10-30
      • 2021-04-21
      • 1970-01-01
      • 2010-12-09
      • 2017-01-04
      相关资源
      最近更新 更多