Xamarin.Forms - 如何使用 Measure() 复制标签和尺寸?尝试自动调整字体大小。 (挠头!)
Xamarin.Forms - How to copy Label and size with Measure()? Trying to auto size font. (Head scratcher!)
有一个名为 Empirical Font Size 的很棒的 Xamarin.Forms 示例项目,它计算 Label
在其包含视图中的最大可能字体大小。它获取有问题的标签,使用 VisualElement.Measure()
根据其属性获取标签的一些大小请求,并将请求的大小与容器的大小进行比较,以查看标签是否适合该字体大小。它会重新计算,直到找到最合适的。它很好用,但我想修改它以做更多事情。
不幸的是,我在修改过程中遇到了一些棘手的障碍,我不确定它们是否更多地与 C# 或 Xamarin 相关。这是我想做的。
- 将计算提取到自己的函数中,以便在任何地方使用。 -> 原来没有这样做。这一点实际上已经完成,但以下目标没有奏效,因此最好将其作为起点。
- (FOCUS HERE) 避免在函数中使用原始标签数据。 (复制一份。) -> 我正在添加一些功能,要求我在计算尺寸时主动更改标签文本数据,但修改我正在调整尺寸的标签可能会导致问题(并非总是与尺寸有关,但以其他方式)。我需要一种方法来复制字体大小标签以保护原始数据。 (更多关于我在下面尝试过的内容)。
- 抽象函数以允许调整其他视图的大小。 -> 现在,这只计算最大标签字体大小。如果可能的话,我想支持其他视图(如选择器、条目等)的自动字体大小调整。在找出 #2 时深思熟虑。
目标 #2 是我遇到问题的地方。 我找不到复制标签然后对临时副本执行大小计算的方法。这是我尝试过的方法以及每次尝试失败的原因。
- 制作一个浅表副本。(例如
Label copyLabel = origLabel;
)-> 正如预期的那样,这不起作用,因为新标签副本仍然引用相同的原始标签内存中的数据。所以如果我设置copyLabel.Text = "hello"
,那么origLabel.Text
也会变成“hello”。不好。
- JSON copy -> 我已经看到 recommendations to use JSON converters 序列化然后反序列化视图以进行快速深度复制,但我当我尝试这个时出现异常。关于标签子项上的
self-referencing loop
的事情。(标签甚至有子项吗??)
- ICloneable -> 我将 运行 这个函数放在静态 class 中,所以我不能这样做。不过,这可能并不重要,因为下一次尝试。
- 创建一个新的 Label 对象并复制一些值。 -> 这似乎可行,但这里的问题是
VisualElement.Measure()
计算。新标签缺少计算正常工作所需的内容,我不知道那是什么。
要使其中任何一个起作用,我需要复制标签,立即对副本执行计算,并将生成的字体大小应用于原始标签。然后副本消失。噗!不幸的是,我所做的任何副本都会导致不同的计算,所以这就是我目前遇到的问题。
有人在别处提到,可能调整大小不起作用,因为新标签不是布局的一部分,因此无法调整大小,但他们没有解释,所以我不明白它们是什么到达。
要了解哪些有效,哪些无效,这里有一个小型 Xamarin 示例项目,其中包含 Empirical Font Size 项目的修改版本。这是一个简单的 A/B 测试。具有相同文本的两个标签由两个几乎相同的函数调整大小——一个使用原始标签,另一个尝试使用副本。它们应该填充提供的堆栈布局的上半部分和下半部分,但副本不起作用。我想帮助完成这项工作。
修改后的示例项目: https://drive.google.com/file/d/1mWxE3p6u53jkIdaIEFVFnkI7BC-kfske/view?usp=sharing
我想出了一个安全、简单的解决方法来解决这个问题,我称之为 'ghost sizing'。您可以创建一个不可见的 'ghost label' 并将其放入将调整标签大小的页面中。它是不可见的,所以它根本不会改变布局,但它仍然可以用于尺寸计算。您将要调整大小的标签的文本传递到 ghost 标签,将 ghost 标签调整为所需 space,并将返回的大小值应用于目标标签。
XAML:
<!-- for sizing other elements without breaking bindings -->
<Label x:Name="ghostLabel" IsVisible="false" />
C#code-behind:
ghostLabel.Text = String.Copy(myLabel.Text);
...
double labelFontSize = ...// do font size calculations here using the ghostLabel object
...
myLabel.FontSize = labelFontSize;
如果你好奇的话,我已经为这个做了我自己的字体大小class。
有一个名为 Empirical Font Size 的很棒的 Xamarin.Forms 示例项目,它计算 Label
在其包含视图中的最大可能字体大小。它获取有问题的标签,使用 VisualElement.Measure()
根据其属性获取标签的一些大小请求,并将请求的大小与容器的大小进行比较,以查看标签是否适合该字体大小。它会重新计算,直到找到最合适的。它很好用,但我想修改它以做更多事情。
不幸的是,我在修改过程中遇到了一些棘手的障碍,我不确定它们是否更多地与 C# 或 Xamarin 相关。这是我想做的。
- 将计算提取到自己的函数中,以便在任何地方使用。 -> 原来没有这样做。这一点实际上已经完成,但以下目标没有奏效,因此最好将其作为起点。
- (FOCUS HERE) 避免在函数中使用原始标签数据。 (复制一份。) -> 我正在添加一些功能,要求我在计算尺寸时主动更改标签文本数据,但修改我正在调整尺寸的标签可能会导致问题(并非总是与尺寸有关,但以其他方式)。我需要一种方法来复制字体大小标签以保护原始数据。 (更多关于我在下面尝试过的内容)。
- 抽象函数以允许调整其他视图的大小。 -> 现在,这只计算最大标签字体大小。如果可能的话,我想支持其他视图(如选择器、条目等)的自动字体大小调整。在找出 #2 时深思熟虑。
目标 #2 是我遇到问题的地方。 我找不到复制标签然后对临时副本执行大小计算的方法。这是我尝试过的方法以及每次尝试失败的原因。
- 制作一个浅表副本。(例如
Label copyLabel = origLabel;
)-> 正如预期的那样,这不起作用,因为新标签副本仍然引用相同的原始标签内存中的数据。所以如果我设置copyLabel.Text = "hello"
,那么origLabel.Text
也会变成“hello”。不好。 - JSON copy -> 我已经看到 recommendations to use JSON converters 序列化然后反序列化视图以进行快速深度复制,但我当我尝试这个时出现异常。关于标签子项上的
self-referencing loop
的事情。(标签甚至有子项吗??) - ICloneable -> 我将 运行 这个函数放在静态 class 中,所以我不能这样做。不过,这可能并不重要,因为下一次尝试。
- 创建一个新的 Label 对象并复制一些值。 -> 这似乎可行,但这里的问题是
VisualElement.Measure()
计算。新标签缺少计算正常工作所需的内容,我不知道那是什么。
要使其中任何一个起作用,我需要复制标签,立即对副本执行计算,并将生成的字体大小应用于原始标签。然后副本消失。噗!不幸的是,我所做的任何副本都会导致不同的计算,所以这就是我目前遇到的问题。
有人在别处提到,可能调整大小不起作用,因为新标签不是布局的一部分,因此无法调整大小,但他们没有解释,所以我不明白它们是什么到达。
要了解哪些有效,哪些无效,这里有一个小型 Xamarin 示例项目,其中包含 Empirical Font Size 项目的修改版本。这是一个简单的 A/B 测试。具有相同文本的两个标签由两个几乎相同的函数调整大小——一个使用原始标签,另一个尝试使用副本。它们应该填充提供的堆栈布局的上半部分和下半部分,但副本不起作用。我想帮助完成这项工作。
修改后的示例项目: https://drive.google.com/file/d/1mWxE3p6u53jkIdaIEFVFnkI7BC-kfske/view?usp=sharing
我想出了一个安全、简单的解决方法来解决这个问题,我称之为 'ghost sizing'。您可以创建一个不可见的 'ghost label' 并将其放入将调整标签大小的页面中。它是不可见的,所以它根本不会改变布局,但它仍然可以用于尺寸计算。您将要调整大小的标签的文本传递到 ghost 标签,将 ghost 标签调整为所需 space,并将返回的大小值应用于目标标签。
XAML:
<!-- for sizing other elements without breaking bindings -->
<Label x:Name="ghostLabel" IsVisible="false" />
C#code-behind:
ghostLabel.Text = String.Copy(myLabel.Text);
...
double labelFontSize = ...// do font size calculations here using the ghostLabel object
...
myLabel.FontSize = labelFontSize;
如果你好奇的话,我已经为这个做了我自己的字体大小class。