簡體   English   中英

iOS 13:如何在 UIKit/SwiftUI 中調整自定義字體的前導/下降/行高

[英]iOS 13: How can I tweak the leading / descend / line height of a custom font in UIKit / SwiftUI

我正在使用自定義字體,並且渲染以某種方式搞砸了行高,這可能是由於錯誤配置的descentleading (?),因此 g 和 j 在渲染文本的最后一行被截斷。 我認為這可能是這種特定字體的問題,因為 Sketch 也暴露了相關字體的類似問題,但我覺得我對排版測量或字體的了解還不夠。 我發現Typographic Concepts上的這個 Apple 文檔頁面非常有見地。

渲染標簽暴露切斷

我使用 FontLab 的測試版本查看了字體本身,順便說一句,這是我第一次使用的 - 所以我幾乎不知道我在看什么。 看起來 g 確實低於配置的descent ,這似乎是最后一行。 (?)(參見: FontLab 中的字符視圖,顯示 g 的下降部分

通過lineSpacing我可以調整線條本身之間的距離以在前幾行中解決這個問題。 我知道iOS的14會帶來一個辦法修改leading一個的Text中SwiftUI。 但我需要針對 iOS 13,所以這無濟於事。

我也嘗試過 SwiftUI 的Text ,一個普通的UILabel.textUILabel.attributedText ,帶有自定義的段落樣式,但我在那里調整的任何東西似乎都沒有緩解這個問題。 視圖甚至沒有剪輯。 只是向框架添加填充根本沒有幫助。 它增加了距離,但 g 和 j 仍然被切斷。

我能做什么? 當最后一行有 ag 和 j 時,繼承UILabel並覆蓋intrinsicContentSize以添加一些額外的空間? 感覺 a) 臟 b) 考慮到填充沒有幫助,它可能無法解決問題?

字體本身是這里的問題嗎? 我可以以某種方式修補字體而不會使它變得更糟嗎?

當我使用較低級別的 API 時,有什么方法可以修改字體的前導或下降高度? 似乎我可以轉到 CoreText,因為CTFontCreateCopyWithAttributes(_:_:_:_:)是候選對象,如果我可以通過屬性修改前導、行距或下降? 可以或猴子補丁/ swizzle 東西而不會射中自己的膝蓋嗎? 我應該 向雷達 提交反饋嗎?

您需要使用NSAttributedString而不是 String 來控制 UILabel 的行距。 這是示例代碼

let style = NSMutableParagraphStyle()
style.lineSpacing = 20
let string  = NSMutableAttributedString(string: "The quick brown fox jumps over the lazy dog, The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog")
string.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, string.length))
let label = UILabel(frame: CGRect(x: 20, y: 100, width: 300, height: 500))
label.attributedText = string
label.numberOfLines = 0
self.view.addSubview(label)

輸出

在此處輸入圖片說明

我知道您在問什么,因為我遇到了與自定義字體相同的問題。 我將提供兩種解決方案。 在我自己的項目中,我按照您的建議覆蓋了 internalContentSize 並為高度和寬度添加了一個填充乘數。 在我的例子中,字體是面向用戶的,所以我有一個包含所有相關信息的結構。 僅供參考 Chalkduster 在系統和剪輯中。 我也相信這都是字體文件本身造成的。

解決方案 1:示例:

struct UserFont{
    var name : String
    var displayName : String
    var widthMultiplier : CGFloat
    var heightMultiplier : CGFloat
}   

然后在我的 UILabel 中,我將其子類化為使用這兩個指標

@IBDesignable
class MultiplierUILabel: UILabel {
    @IBInspectable var widthPaddingMultiplier : CGFloat = 1
    @IBInspectable var heightPaddingMultiplier : CGFloat = 1
    override var intrinsicContentSize: CGSize{
       return CGSize(width: super.intrinsicContentSize.width * widthPaddingMultiplier, height: super.intrinsicContentSize.height * heightPaddingMultiplier)
    }
}

這對我來說是最簡單的實現,因為我找到了相應的字體和乘數比例。

解決方案2:
您可以通過測量字形邊界並調整原點 y 來使繪制發生得稍高一些。 例如,這修復了系統中包含的 Chalkduster 字體的剪輯。

@IBDesignable
class PaddingUILabel: UILabel {
    override func drawText(in rect:CGRect) {
        //hello
        guard let labelText = text else {  return super.drawText(in: rect) }
        //just some breathing room
        let info = boundsForAttrString(str: labelText, font: self.font!, kern: .leastNormalMagnitude)
        let glyph = info.glyph
        var newRect = rect
        let glyphPadding = -(glyph.origin.y)
        if glyphPadding - info.descent > 1 && info.descent != 0{
            newRect.origin.y -= glyphPadding/2
        }else{
            if info.descent != 0{
                newRect.origin.y += (info.descent - glyphPadding)/2
            }
        }
        super.drawText(in: newRect)
    }
    
    func boundsForAttrString(str:String,font:UIFont,kern:CGFloat)->(glyph:CGRect,descent:CGFloat){
        let attr = NSAttributedString(string: str, attributes: [.font:font,.kern:kern])
        let line = CTLineCreateWithAttributedString(attr)
        var ascent : CGFloat = 0
        var descent : CGFloat = 0
        var leading : CGFloat = 0
        
        CTLineGetTypographicBounds(line, &ascent, &descent, &leading)
        let glyph = CTLineGetBoundsWithOptions(line, .useGlyphPathBounds).integral
        return (glyph,leading != 0 ? descent : 0)
    }
}

方案二的結果:系統系統

使用字形邊界的 PaddingUILabel 填充UI標簽

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM