MAUI 中没有 ICanvas 实例可以测量文本字符串大小吗?

问题描述 投票:0回答:2

我可以使用 ICanvas.GetStringSize 方法在 IDrawable 对象的 Draw 方法调用中测量文本字符串大小。

现在,如果我需要在绘图之前测量文本字符串怎么办?例如,在我的用例中,可绘制对象的边界框(Draw 方法调用中的第二个参数)由给定字体大小的父 ContentView 设置,方法是计算文本可以采用的最大大小此字体大小的字符串。这用下面的伪代码来说明:

private void OnFontSizeChanged(int fontSize)
{
    // The string possible values are integers in the [1-9999] range
    var maxTextSize = GetStringSize("9999", fontSize);
    
    // Now we know the font size, we can set the GraphicsView object size once
    // according to the maximum width/height that can be taken by the child drawing.
    HeightRequest = maxTextSize.Height * 1.2f;
    WidthRequest = maxTextSize.Width * 1.2f;
} 

在我描述的场景中,有没有一种方法可以不使用 ICanvas 来测量文本大小?感谢您对此的任何意见。

c# xaml graphics maui
2个回答
1
投票

我在我的一个项目中使用了

Label.Measure
,试图进行一些响应式字体缩放。您也许可以根据您的目的对其进行调整。就我而言,基本思想是根据测量的大小进行二分搜索。

根据一些初步实验,如果想使用虚拟标签进行测量,似乎标签“does”需要位于可视化树中的某个位置,但“doesn't”需要可见。


public partial class MainPage : ContentPage { public MainPage() => InitializeComponent(); private void AnySizeChanged(object sender, EventArgs e) { if(sender is Label label) { double minFontSize = 1; double maxFontSize = 100; double tolerance = 0.1; double targetHeight = label.Height * 0.9; double targetWidth = label.Width * 0.8; while (minFontSize < maxFontSize) { double midFontSize = (minFontSize + maxFontSize) / 2; label.FontSize = midFontSize; Size textSize = label.Measure(double.PositiveInfinity, double.PositiveInfinity).Request; bool isHeightWithinTolerance = Math.Abs(textSize.Height - targetHeight) <= targetHeight * tolerance; bool isWidthWithinLabel = textSize.Width <= targetWidth; if (isHeightWithinTolerance && isWidthWithinLabel) { break; } else if (textSize.Height > targetHeight || textSize.Width > targetWidth) { maxFontSize = midFontSize - 0.1; } else { minFontSize = midFontSize + 0.1; } } label.FontSize = (minFontSize + maxFontSize) / 2; } } }

在xaml中,处理SizeChanged事件。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DynamicSizingProto"
             x:Class="DynamicSizingProto.MainPage">
    <ContentPage.Resources>
        <Style TargetType="Label">
            <Setter Property="HorizontalTextAlignment" Value="Center" />
            <Setter Property="VerticalTextAlignment" Value="Center" />
            <Setter Property="Margin" Value="5" />
            <Setter Property="BackgroundColor" Value="{StaticResource Secondary}" />
            <Setter Property="TextColor" Value="{StaticResource Primary}" />
        </Style>
    </ContentPage.Resources>
    <Grid
        RowDefinitions="*,*,2*,3*,4*,*">
        <Label
            Text="Text Placeholder"
            SizeChanged="AnySizeChanged"
            Grid.Row="1"/>
        <Label
            Text="Text Placeholder"
            SizeChanged="AnySizeChanged"
            Grid.Row="2"/>
        <Label
            Text="Text Placeholder"
            SizeChanged="AnySizeChanged"
            Grid.Row="3"/>
        <Label
            Text="Text Placeholder"
            SizeChanged="AnySizeChanged"
            Grid.Row="4"/>
    </Grid>
</ContentPage>

我可能会尝试将其烘焙成自定义扩展

LabelEx
,但这是基本想法。

iPad


对于任何处理类似问题的人,这是我根据 IV 建议的解决方案所做的。


0
投票

现在已经计算了大小,GraphicsView 调用 Invalidate,因此再次调用 Draw 方法,但现在知道了不同图形元素的适当大小。

图形查看代码:

public ValueOutOfTotal() { Drawable = ValueOutOfTotalDrawable = new ValueOutOfTotalDrawable(); SizeChanged += ValueOutOfTotal_SizeChanged; ValueOutOfTotalDrawable.RequiredSizeComputed += ValueOutOfTotalDrawable_RequiredSizeComputed; } private void ValueOutOfTotalDrawable_RequiredSizeComputed(object? sender, EventArgs e) { if (e is SizeComputedEventArgs sizeComputedEventArgs) { Invalidate(); } } private void ValueOutOfTotal_SizeChanged(object? sender, EventArgs e) { ValueOutOfTotalDrawable.MustComputeRequiredSize = true; }

IDrawable 代码:(ComputeRequiredSize 方法当然要使用有关您要绘制的内容的信息来实现)

    public void Draw(ICanvas canvas, RectF dirtyRect)
    {
        if (MustComputeRequiredSize)
        {
            _sizeInfo = ComputeRequiredSize(canvas, dirtyRect);
            MustComputeRequiredSize = false;
            RequiredSizeComputed?.Invoke(this, EventArgs.Empty);
        }
        else
        {
            Draw(canvas, dirtyRect, ValueColor, TotalColor, SeparatorColor, TitleColor, ValueFontSize, TotalFontSize, TitleFontSize, Value, Total, Title, _sizeInfo);
        }
    }

© www.soinside.com 2019 - 2024. All rights reserved.