【Delphi】开发IOS 程序,TLabel 中英文字对齐(水平),一行代码解决显示对齐问题!

目录

一、问题现象:

二、解决方案(一行代码解决ios对齐问题):

三、解决后效果:

四、后记:


一、问题现象:

在用 Delphi 开发ios程序时,使用TLabel控件显示,会出现中英文无法水平对齐,英文字符会靠上大概少半行,看起来很不协调。

如下图所示:

出现这样的问题,从 ios 9 开始就一直存在。目前测试的11.3仍然存在这个问题!所以特写出此解决方案,以方便需要的朋友!

二、解决方案(一行代码解决ios对齐问题):

由于 Delphi 的版本比较多,不同的版本解决方案基本一致,但都是需要修该对应版本的FMX.FontGlyphs.iOS.pas文件。如果默认安装,一般该文件位于C:\Program Files (x86)\Embarcadero\Studio\22.0\source\fmx目录下,注意22.0表示版本,不同的版本这个数字不一样。

  1. 找到 FMX.FontGlyphs.iOS.pas 这个文件;
  2. 将该文件拷贝到你的工程文件目录下(也就是你正在开发的工程文件);
  3. 修改拷贝后的 FMX.FontGlyphs.iOS.pas 文件;

本文使用的是D11.3版本,修改 FMX.FontGlyphs.iOS.pas 这个文件中的这个过程 GetDefaultBaseline 。就是修改205行,将 Chars := 'a' ; 修改为 Chars := '中';

重点:

在工程文件中引用修改后的 FMX.FontGlyphs.iOS.pas 文件。

{$IFDEF IOS}

FMX.FontGlyphs.iOS, //IOS 对齐

{$ENDIF}

修改前文件

Delphi 复制代码
{*******************************************************}
{                                                       }
{             Delphi FireMonkey Platform                }
{ Copyright(c) 2012-2023 Embarcadero Technologies, Inc. }
{              All rights reserved                      }
{                                                       }
{*******************************************************}

unit FMX.FontGlyphs.iOS;

interface

{$SCOPEDENUMS ON}

uses
  System.Math, System.Types, System.Classes, System.SysUtils, System.UITypes, System.UIConsts, System.Generics.Collections,
  System.Generics.Defaults, Macapi.ObjectiveC, Macapi.CoreFoundation, iOSapi.CocoaTypes, iOSapi.CoreGraphics,
  iOSapi.Foundation, iOSapi.CoreText, iOSapi.UIKit, FMX.Types, FMX.Surfaces, FMX.FontGlyphs;

type
  TIOSFontGlyphManager = class(TFontGlyphManager)
  const
    BoundsLimit = $FFFF;
  private
    FColorSpace: CGColorSpaceRef;
    FFontRef: CTFontRef;
    FColoredEmojiFontRef: CTFontRef;
    FDefaultBaseline: Single;
    FDefaultVerticalAdvance: Single;
    procedure GetDefaultBaseline;
    function GetFontDescriptor: CTFontDescriptorRef;
    function CGColorCreate(const AColor: TAlphaColor): CGColorRef;
    function CTFrameCreate(const APath: CGMutablePathRef; const ACharacter: string): CTFrameRef;
  protected
    procedure LoadResource; override;
    procedure FreeResource; override;
    function DoGetGlyph(const ACharacter: UCS4String; const Settings: TFontGlyphSettings;
      const UseColorfulPalette: Boolean): TFontGlyph; override;
    function DoGetBaseline: Single; override;
    function IsColorfulCharacter(const ACharacter: UCS4String): Boolean; override;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses
  System.Character, System.Math.Vectors, Macapi.Helpers, FMX.Graphics, FMX.Consts, FMX.Utils;

//........ 此处省略了代码

procedure TIOSFontGlyphManager.GetDefaultBaseline;
var
  Chars: string;
  Str: CFStringRef;
  Frame: CTFrameRef;
  Attr: CFMutableAttributedStringRef;
  Path: CGMutablePathRef;
  Bounds: CGRect;
  FrameSetter: CTFramesetterRef;
  // Metrics
  Line: CTLineRef;
  Lines: CFArrayRef;
  Runs: CFArrayRef;
  Run: CTRunRef;
  Ascent, Descent, Leading: CGFloat;
  BaseLinePos: CGPoint;
begin
  Path := CGPathCreateMutable();
  Bounds := CGRectMake(0, 0, BoundsLimit, BoundsLimit);
  CGPathAddRect(Path, nil, Bounds);
  Chars := 'a';
  Str := CFStringCreateWithCharacters(kCFAllocatorDefault, PChar(Chars), 1);

  Attr := CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
  CFAttributedStringReplaceString(Attr, CFRangeMake(0, 0), Str);

  CFAttributedStringBeginEditing(Attr);
  try
    // Font
    if FFontRef <> nil then
      CFAttributedStringSetAttribute(Attr, CFRangeMake(0, 1), kCTFontAttributeName, FFontRef);
  finally
    CFAttributedStringEndEditing(Attr);
  end;

  FrameSetter := CTFramesetterCreateWithAttributedString(CFAttributedStringRef(Attr));
  CFRelease(Attr);

  Frame := CTFramesetterCreateFrame(FrameSetter, CFRangeMake(0, 0), Path, nil);
  CFRelease(FrameSetter);
  CFRelease(Str);

  // Metrics
  Lines := CTFrameGetLines(Frame);
  Line := CTLineRef(CFArrayGetValueAtIndex(Lines, 0));
  Runs := CTLineGetGlyphRuns(Line);
  Run := CFArrayGetValueAtIndex(Runs, 0);
  CTRunGetTypographicBounds(Run, CFRangeMake(0, 1), @Ascent,  @Descent, @Leading);

  CTFrameGetLineOrigins(Frame, CFRangeMake(0, 0), @BaseLinePos);
  FDefaultBaseline := BoundsLimit - BaseLinePos.y;

  FDefaultVerticalAdvance := FDefaultBaseline + Descent;

  CFRelease(Frame);
  CFRelease(Path);
end;

//........ 此处省略了代码

修改后文件

Delphi 复制代码
{*******************************************************}
{                                                       }
{             Delphi FireMonkey Platform                }
{ Copyright(c) 2012-2023 Embarcadero Technologies, Inc. }
{              All rights reserved                      }
{                                                       }
{*******************************************************}

unit FMX.FontGlyphs.iOS;

interface

{$SCOPEDENUMS ON}

uses
  System.Math, System.Types, System.Classes, System.SysUtils, System.UITypes, System.UIConsts, System.Generics.Collections,
  System.Generics.Defaults, Macapi.ObjectiveC, Macapi.CoreFoundation, iOSapi.CocoaTypes, iOSapi.CoreGraphics,
  iOSapi.Foundation, iOSapi.CoreText, iOSapi.UIKit, FMX.Types, FMX.Surfaces, FMX.FontGlyphs;

type
  TIOSFontGlyphManager = class(TFontGlyphManager)
  const
    BoundsLimit = $FFFF;
  private
    FColorSpace: CGColorSpaceRef;
    FFontRef: CTFontRef;
    FColoredEmojiFontRef: CTFontRef;
    FDefaultBaseline: Single;
    FDefaultVerticalAdvance: Single;
    procedure GetDefaultBaseline;
    function GetFontDescriptor: CTFontDescriptorRef;
    function CGColorCreate(const AColor: TAlphaColor): CGColorRef;
    function CTFrameCreate(const APath: CGMutablePathRef; const ACharacter: string): CTFrameRef;
  protected
    procedure LoadResource; override;
    procedure FreeResource; override;
    function DoGetGlyph(const ACharacter: UCS4String; const Settings: TFontGlyphSettings;
      const UseColorfulPalette: Boolean): TFontGlyph; override;
    function DoGetBaseline: Single; override;
    function IsColorfulCharacter(const ACharacter: UCS4String): Boolean; override;
  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses
  System.Character, System.Math.Vectors, Macapi.Helpers, FMX.Graphics, FMX.Consts, FMX.Utils;

//........ 此处省略了代码

procedure TIOSFontGlyphManager.GetDefaultBaseline;
var
  Chars: string;
  Str: CFStringRef;
  Frame: CTFrameRef;
  Attr: CFMutableAttributedStringRef;
  Path: CGMutablePathRef;
  Bounds: CGRect;
  FrameSetter: CTFramesetterRef;
  // Metrics
  Line: CTLineRef;
  Lines: CFArrayRef;
  Runs: CFArrayRef;
  Run: CTRunRef;
  Ascent, Descent, Leading: CGFloat;
  BaseLinePos: CGPoint;
begin
  Path := CGPathCreateMutable();
  Bounds := CGRectMake(0, 0, BoundsLimit, BoundsLimit);
  CGPathAddRect(Path, nil, Bounds);
  Chars := '中';
  //Chars := 'a';
  Str := CFStringCreateWithCharacters(kCFAllocatorDefault, PChar(Chars), 1);

  Attr := CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
  CFAttributedStringReplaceString(Attr, CFRangeMake(0, 0), Str);

  CFAttributedStringBeginEditing(Attr);
  try
    // Font
    if FFontRef <> nil then
      CFAttributedStringSetAttribute(Attr, CFRangeMake(0, 1), kCTFontAttributeName, FFontRef);
  finally
    CFAttributedStringEndEditing(Attr);
  end;

  FrameSetter := CTFramesetterCreateWithAttributedString(CFAttributedStringRef(Attr));
  CFRelease(Attr);

  Frame := CTFramesetterCreateFrame(FrameSetter, CFRangeMake(0, 0), Path, nil);
  CFRelease(FrameSetter);
  CFRelease(Str);

  // Metrics
  Lines := CTFrameGetLines(Frame);
  Line := CTLineRef(CFArrayGetValueAtIndex(Lines, 0));
  Runs := CTLineGetGlyphRuns(Line);
  Run := CFArrayGetValueAtIndex(Runs, 0);
  CTRunGetTypographicBounds(Run, CFRangeMake(0, 1), @Ascent,  @Descent, @Leading);

  CTFrameGetLineOrigins(Frame, CFRangeMake(0, 0), @BaseLinePos);
  FDefaultBaseline := BoundsLimit - BaseLinePos.y;

  FDefaultVerticalAdvance := FDefaultBaseline + Descent;

  CFRelease(Frame);
  CFRelease(Path);
end;

//........ 此处省略了代码

三、解决后效果:

已经全部水平对齐,完美解决!

四、后记:

记得当时在使用D10.1 berlin的时候,就存在这个问题。中间一直在没有用Delphi开发过ios程序,当时以为高版本的Delphi 可能会解决这个问题,没想到D11.3仍然存在这个问题,不知道是否是在什么地方配置下就可以解决(如果确实有知道的请留言告知)。幸好当时解决有记录,今天遇到问题还可以继续使用。这要感谢妈妈教我的:闲时收拾,忙时用!

相关推荐
人月神话Lee1 天前
我做了个不要账号、不要定位权限的旅行 App,聊聊那些「不做」的决定
ios·ai编程·产品
2501_916007472 天前
Bundle ID 注册与管理 App ID 创建指南 命名规则 权限开关与删除注意事项
android·ios·小程序·https·uni-app·iphone·webview
2501_915909062 天前
iOS 证书创建与管理 类型限制 p12 密码与云备份实操
android·ios·小程序·https·uni-app·iphone·webview
00后程序员张2 天前
有没有更轻量的 iOS 开发环境?快蝎kxapp轻量化路径与构成
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
ii_best2 天前
iOS 投屏ios群控鹰眼中控系统安装指南|电脑端 + TestFlight + 开发者模式实操
ios·自动化·按键精灵
CHB4 天前
uni-app x 蒸汽模式 性能测试基准报告 Benchmark【Android版】
android·ios·uni-app
Magic-ZYJ4 天前
不登录、不联网也能用:我是如何设计一款“本地优先”iOS App 的
ios·app·iphone·研发·独立开发者·心情日记
_阿南_4 天前
flutter 展示的字体突然奔放了
android·flutter·ios
90后的晨仔4 天前
你的 iOS 最低部署版本即将不再被 App Store 接受
ios