我们有时需要手动计算文本内容显示所需要占用的区域大小,在 VCL 中相信大家都很熟悉怎么做了。但在 FMX 中如何去跨平台的实现它,这就需要研究研究了,毕竟连 FMX 自带的 TLabel 的 AutoSize 设置为 true 都没产生任何效果。
好吧,首先看看我们要包含的单元:
- FMX.TextLayout :我们需要 TTextLayout 实例来计算文本内容的显示区域
- FMX.Graphics :我们需要它提供 TCanvasManager.MeasureCanvas 用于计算文本内容显示区域大小的画布
- FMX.Objects :我们需要 TText 来取得样式中的字体设置(当然,如果你不使用样式来控制控件的字体大小,则请忽略它)
接下来,我们来看看如何实现这个计算的过程:
- 首先,我们要确保我们使用的是正确的字体。如果一个控件,如 TLabel 使用了样式的字体,我们计算时就必需使用样式的字体,否则应该使用控件本身的字体设置。
- 其次,我们计算时要设置一堆属性,最后直接取 TTextLayout 实例的 TextRect 就是内容占据的区域。由于面要更改 TTextLayout 实例的多个属性,我们最好调用 BeginUpdate/EndUpdate 来提高效率。
好了,我们来看实现:
function CalcTextRect(S: String; ASettings: TTextSettings; const AMaxWidth: Single): TRectF; var ATextLayout: TTextLayout; begin Result := TRectF.Create(0, 0, AMaxWidth, MaxInt); ATextLayout := TTextLayoutManager.TextLayoutByCanvas (TCanvasManager.MeasureCanvas.ClassType) .Create(TCanvasManager.MeasureCanvas); try ATextLayout.BeginUpdate; ATextLayout.Font.Assign(ASettings.Font); ATextLayout.HorizontalAlign := ASettings.HorzAlign; ATextLayout.WordWrap:=ASettings.WordWrap; ATextLayout.Text := S; ATextLayout.EndUpdate; Result:=ATextLayout.TextRect; finally ATextLayout.DisposeOf; end; end;
我们测试一下效果:
procedure TForm2.Button1Click(Sender: TObject); var ARect: TRectF; begin ARect:=CalcTextRect(Memo1.Text,Label1.ResultingTextSettings,ClientWidth); Label1.Height := ARect.Height; Label1.Width := ARect.Width; Label1.Text := Memo1.Text; end;
其中,我们在 Label1 中设置了一个 TRectangle,对齐方式为 Content,填充样式设置为 None,实际运行效果如下图:
等等,你说你前面要引用 TText 对象,这里也没见到呀!甭着急,上面的代码根本没考虑千变万化的变态样式。如果我们要考虑样式,则需要查找 Label1 所有的子控件中,类型为 TText,StyleName 为 text 的对象,然后计算它相对于 Label1 边缘的位置,然后再计算额外要添加的上、下、左、右空间,才能真正得出最终需要的矩形区域,不过这里就不啰嗦了,自己去玩吧。
如果考虑到多次重复执行测试,最好单独定义一个类,将 TTextLayout 实例缓存来下,避免不必要的重复创建。