目錄
一、問題現象:
二、解決方案(一行代碼解決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表示版本,不同的版本這個數字不一樣。
- 找到 FMX.FontGlyphs.iOS.pas?這個文件;
- 將該文件拷貝到你的工程文件目錄下(也就是你正在開發的工程文件);
- 修改拷貝后的?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 FireMonkey Platform }
{ Copyright(c) 2012-2023 Embarcadero Technologies, Inc. }
{ All rights reserved }
{ }
{*******************************************************}unit FMX.FontGlyphs.iOS;interface{$SCOPEDENUMS ON}usesSystem.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;typeTIOSFontGlyphManager = class(TFontGlyphManager)constBoundsLimit = $FFFF;privateFColorSpace: 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;protectedprocedure 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;publicconstructor Create;destructor Destroy; override;end;implementationusesSystem.Character, System.Math.Vectors, Macapi.Helpers, FMX.Graphics, FMX.Consts, FMX.Utils;//........ 此處省略了代碼procedure TIOSFontGlyphManager.GetDefaultBaseline;
varChars: string;Str: CFStringRef;Frame: CTFrameRef;Attr: CFMutableAttributedStringRef;Path: CGMutablePathRef;Bounds: CGRect;FrameSetter: CTFramesetterRef;// MetricsLine: CTLineRef;Lines: CFArrayRef;Runs: CFArrayRef;Run: CTRunRef;Ascent, Descent, Leading: CGFloat;BaseLinePos: CGPoint;
beginPath := 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// Fontif FFontRef <> nil thenCFAttributedStringSetAttribute(Attr, CFRangeMake(0, 1), kCTFontAttributeName, FFontRef);finallyCFAttributedStringEndEditing(Attr);end;FrameSetter := CTFramesetterCreateWithAttributedString(CFAttributedStringRef(Attr));CFRelease(Attr);Frame := CTFramesetterCreateFrame(FrameSetter, CFRangeMake(0, 0), Path, nil);CFRelease(FrameSetter);CFRelease(Str);// MetricsLines := 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 FireMonkey Platform }
{ Copyright(c) 2012-2023 Embarcadero Technologies, Inc. }
{ All rights reserved }
{ }
{*******************************************************}unit FMX.FontGlyphs.iOS;interface{$SCOPEDENUMS ON}usesSystem.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;typeTIOSFontGlyphManager = class(TFontGlyphManager)constBoundsLimit = $FFFF;privateFColorSpace: 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;protectedprocedure 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;publicconstructor Create;destructor Destroy; override;end;implementationusesSystem.Character, System.Math.Vectors, Macapi.Helpers, FMX.Graphics, FMX.Consts, FMX.Utils;//........ 此處省略了代碼procedure TIOSFontGlyphManager.GetDefaultBaseline;
varChars: string;Str: CFStringRef;Frame: CTFrameRef;Attr: CFMutableAttributedStringRef;Path: CGMutablePathRef;Bounds: CGRect;FrameSetter: CTFramesetterRef;// MetricsLine: CTLineRef;Lines: CFArrayRef;Runs: CFArrayRef;Run: CTRunRef;Ascent, Descent, Leading: CGFloat;BaseLinePos: CGPoint;
beginPath := 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// Fontif FFontRef <> nil thenCFAttributedStringSetAttribute(Attr, CFRangeMake(0, 1), kCTFontAttributeName, FFontRef);finallyCFAttributedStringEndEditing(Attr);end;FrameSetter := CTFramesetterCreateWithAttributedString(CFAttributedStringRef(Attr));CFRelease(Attr);Frame := CTFramesetterCreateFrame(FrameSetter, CFRangeMake(0, 0), Path, nil);CFRelease(FrameSetter);CFRelease(Str);// MetricsLines := 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仍然存在這個問題,不知道是否是在什么地方配置下就可以解決(如果確實有知道的請留言告知)。幸好當時解決有記錄,今天遇到問題還可以繼續使用。這要感謝媽媽教我的:閑時收拾,忙時用!