第五章:尺寸处理(6)

简介: 经验拟合文本在具有特定尺寸的矩形内拟合文本的另一种方法涉及基于特定字体大小凭经验确定呈现文本的大小,然后向上或向下调整该字体大小。 无论可访问性设置如何,此方法都具有在所有设备上工作的优势。但是这个过程可能很棘手:第一个问题是字体大小和渲染文本的高度之间没有干净的线性关系。

经验拟合文本
在具有特定尺寸的矩形内拟合文本的另一种方法涉及基于特定字体大小凭经验确定呈现文本的大小,然后向上或向下调整该字体大小。 无论可访问性设置如何,此方法都具有在所有设备上工作的优势。
但是这个过程可能很棘手:第一个问题是字体大小和渲染文本的高度之间没有干净的线性关系。 随着文本相对于其容器的宽度变大,会导致更多的换行符,并带来更多的空间浪费。 寻找最佳字体大小的计算通常涉及缩小该值的循环。
第二个问题涉及获取以特定字体大小呈现的标签大小的实际机制。 您可以在Label上设置SizeChanged处理程序,但在该处理程序中,您不希望进行任何更改(如设置新的FontSize属性),这会导致对该处理程序的递归调用。
更好的方法是调用由VisualElement定义的GetSizeRequest方法,并由Label和所有其他视图继承。 GetSizeRequest需要两个参数 - 宽度约束和高度约束。 这些值表示要在其中拟合元素的矩形的大小,其中一个或另一个可以是无限大。 通过标签使用GetSizeRequest时,通常将宽度约束参数设置为容器的宽度,将高度约束设置为Double.PositiveInfinity。
GetSizeRequest方法返回一个SizeRequest类型的值,这是一个带有两个适当的结构的结构,名为Request和Minimum,都是Size类型。 Request属性表示呈现文本的大小。 (关于这个和相关方法的更多信息可以在第26章中找到。)
EmpiricalFontSize项目演示了这种技术。 为了方便起见,它定义了一个名为FontCalc的小型结构,其构造函数针对特定Label(已用文本初始化)调用GetSizeRequest,试用字体大小和文本宽度:

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.GetSizeRequest(containerWidth, Double.PositiveInfinity);
        // Save that height.
        TextHeight = sizeRequest.Request.Height;
    }
    public double FontSize { private set; get; }
    public double TextHeight { private set; get; }
}

渲染标签的合成高度保存在TextHeight属性中。
当您在页面或布局上调用GetSizeRequest时,页面或布局需要通过可视化树来查看所有子项的大小。 这当然会带来性能上的损失,所以除非必要,否则应该避免拨打电话。 但是一个Label没有孩子,所以在一个Label上调用GetSizeRequest并不是那么糟糕。 但是,您仍然应该尝试优化呼叫。 避免循环访问一系列字体大小值,以确定不会导致文本超过容器高度的最大值。 在算法上缩小最佳值的过程更好。
GetSizeRequest要求该元素是可视化树的一部分,并且布局过程至少部分开始。 不要在页面类的构造函数中调用GetSizeRequest。 你不会从中获得信息。 第一个合理的机会是覆盖页面的OnAppearing方法。 当然,您目前可能没有足够的信息将参数传递给GetSizeRequest方法。
但是,调用GetSizeRequest并没有任何副作用。 它不会在元素上设置新的大小,这意味着它不会引发SizeChanged事件,这意味着调用SizeChanged处理程序是安全的。
EmpiricalFontSizePage类实例化承载标签的ContentView的SizeChanged处理程序中的FontCalc值。 每个FontCalc值的构造函数在Label上调用GetSize?Request调用并保存结果TextHeight。 SizeChanged处理程序的初始字体大小为10和100,假定最佳值位于这两者之间,并且它们代表下限和上限。 因此变量名称更低?FontCalc和upperFontCalc:

public class EmpiricalFontSizePage : ContentPage
{
    Label label;
    public EmpiricalFontSizePage()
    {
        label = new Label();
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 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 a paragraph of text displayed with " +
                 "a FontSize value of ?? that is empirically " +
                 "calculated in a loop within the SizeChanged " +
                 "handler of the Label's container. This technique " +
                 "can be tricky: You don't want to get into " +
                 "an infinite loop by triggering a layout pass " +
                 "with every calculation. 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"));
    }
}

在while循环的每次迭代中,这两个FontCalc值的FontSize属性都会保存并获得新的FontCalc。 这成为新的lowerFontCalc或upperFontCalc值,具体取决于渲染文本的高度。 当计算的字体大小在最佳值的一个单位内时,循环结束。
大约七次迭代的循环就足以得到一个明显好于早期程序中计算的估计值的值:
201806132141540335
将手机横向移动触发另一次重新计算,导致类似的(尽管不一定相同)字体大小:
201806132142330336
看起来,除了简单地将FontSize属性与FontCalc的较低和较高值平均以外,算法可以得到改进。 但是字体大小和文本高度之间的关系相当复杂,有时候最简单的方法也是一样的好。

目录
相关文章
|
Android开发 iOS开发
|
Android开发 iOS开发 Windows
|
编解码 Android开发
|
编解码 程序员 Android开发
|
API
《Photoshop图层调整深度剖析》—第2章结论
<span style='letter-spacing:1px'>本节书摘来自异步社区《Photoshop图层调整深度剖析》一书中的第2章结论,作者【美】Scott Valentine,更多章节内容可以访问云栖社区“异步社区”公众号查看。</span>
1462 0
|
前端开发
前端知识案例学习9-可调整尺寸得UI
前端知识案例学习9-可调整尺寸得UI
112 0
前端知识案例学习9-可调整尺寸得UI
|
前端开发 定位技术
(十五)WebGIS中平移功能的设计和实现
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/。 1.前言 这一章我们将详细讲解WebGIS工具栏中另一个基础工具——平移工具(Pan)。
672 0
|
JSON JavaScript 编译器
Qt编写地图综合应用5-自适应拉伸
一、前言 用过echart的人都会遇到一个问题,就算是代码中写了window.onresize = echart.resize,也只是横向自适应拉伸填充页面,垂直方向不会变化,除非指定高度才可以,这就比较郁闷了,为何echart本身不会自适应呢?按道理不应该啊,莫非实现起来很困难?好吧先不管这个了.
686 0
Qt编写地图综合应用5-自适应拉伸