如何根据view.Width动态自动设置FontSize?

时间:2019-03-23 01:31:52

标签: xamarin xamarin.forms fonts runtime font-size

“尝试自动调整大小” img_1 字体大小太大,因此会截断一部分字符串(如果文本太大,则会截断一部分,并用省略号代替)。

“测试文字” img_2 字体大小太小。 fontSize是其各自视图(估计)的三分之一。

如何将Element的fontSize设置为Element(和(或包含Views))宽度的大小?使用上面的示例作为参考-“测试文本”将占据更多视图,而“尝试自动调整大小”将占据更少的视图。

注意:黑框表示其他元素。

所需目标是一个元素(标签和/或包含视图),当在运行时更改文本时,将根据分配的文本和可用的宽度来设置fontSize(在构建后保持不变)。这样所有文本都可以在字符串中查看,并使用可用的宽度。

目的是在缩放比例差异很大的各种设备上支持多个平台。

尝试了什么?基于习语的NamedSizes(电话/平板电脑/等),并基于OS(平台,即IOS,Android等)通过乘法和除法来操作它们。这不是最佳实践,必须有一种方法可以做到这一点。

遵循Xamarin.Forms指南“使文本适合可用大小”或“根据经验适合文本”会产生与预期不符的结果。"CH5: Dealing with sizes"

请为最佳做法和/或后续步骤提供建议。

结构

struct FontCalc
{
    public FontCalc(Label label, double fontSize, double containerWidth)
        : this()
    {
        // Save the font size.
        FontSize = fontSize;

        // Recalculate the Label height.
        label.FontSize = fontSize;
        SizeRequest sizeRequest =
            label.Measure(containerWidth, Double.PositiveInfinity);

        // Save that height.
        TextHeight = sizeRequest.Request.Height;
    }

    public double FontSize { private set; get; }

    public double TextHeight { private set; get; }
}

实施

标签标签;

public EmpiricalFontSizePage()
{
    label = new Label();

    Padding = new Thickness(0, Device.RuntimePlatform == Device.iOS ? 30 : 0, 0, 0);
    ContentView contentView = new ContentView
    {
        Content = label
    };
    contentView.SizeChanged += OnContentViewSizeChanged;
    Content = contentView;
}

void OnContentViewSizeChanged(object sender, EventArgs args)
{
    // Get View whose size is changing.
    View view = (View)sender;

    if (view.Width <= 0 || view.Height <= 0)
        return;

    label.Text =
        "This is text displayed. Does it work?";

    // Calculate the height of the rendered text.
    FontCalc lowerFontCalc = new FontCalc(label, 10, view.Width);
    FontCalc upperFontCalc = new FontCalc(label, 100, view.Width);

    while (upperFontCalc.FontSize - lowerFontCalc.FontSize > 1)
    {
        // Get the average font size of the upper and lower bounds.
        double fontSize = (lowerFontCalc.FontSize + upperFontCalc.FontSize) / 2;

        // Check the new text height against the container height.
        FontCalc newFontCalc = new FontCalc(label, fontSize, view.Width);

        if (newFontCalc.TextHeight > view.Height)
        {
            upperFontCalc = newFontCalc;
        }
        else
        {
            lowerFontCalc = newFontCalc;
        }
    }

    // Set the final font size and the text with the embedded value.
    label.FontSize = lowerFontCalc.FontSize;
    label.Text = label.Text.Replace("??", label.FontSize.ToString("F0"));
}

(上面链接的XF文档中的实现代码)

1 个答案:

答案 0 :(得分:1)

一种解决方案是使用NuGet软件包:Forms9Patch

使用其LinesAutoFit属性,我们可以获得所需的结果。在我们的情况下,我们需要一行,我们希望将FontSize设置为使文本适合一行所需的内容。将Lines = 1AutoFit = Forms9Patch.AutoFit.WidthFontSize设置为一个较大的值(将AutoFit设置为Width会缩小字体,这是否超出我们的期望最大值并不重要直到达到使文本适合我们指定的行数所需的大小)为止,都会导致Label自动将其FontSize调整为给定文本长度的最大可用空间。