Size Calculation and Drawing Errors with Full-Width Punctuation

Requirement
Extract text that fits a specified container size from a long string, ensuring consistent display across different system versions.

Issue
When using layoutManager.enumerateLineFragments from TextKit for line-by-line text segmentation, discrepancies arise at the end of lines when full-width characters or phrases appear. For instance, while TextKit deems a line as fully displayable without breaking, the UI component in iOS 17 forcibly wraps the phrase onto the next line. This issue does not occur in iOS 16 where line ebreaking and segmentation align perfectly.


import SwiftUI

struct SplitTextDemo: View {
    let fontSize: CGFloat = 14
    let containerSize: CGSize = CGSize(width: 300, height: 100)
    
    @State var contentString: String = "18、在一个提示中多次重复某个特定的词短语。nn测试文案是否会发生偏移,查看具体位置和文末。iOS16则不会有这个问题,换行和分割是完全一样,但在iOS17中则会出现显示和textkit裁切不一致的情况。"
    @State var splitString: String = ""
    
    var body: some View {
        VStack {
            Text("Original text:")
            TextField("", text: $contentString, axis: .vertical)
                .font(.system(size: fontSize))
                .frame(width: containerSize.width)
                .background {
                    Color.blue
                }
            
            Text("Extracted text:")
            TextField("", text: $splitString, axis: .vertical)
                .font(.system(size: fontSize))
                .frame(width: containerSize.width, height: containerSize.height)
                .background {
                    Color.orange
                }
        }
        .onChange(of: contentString, perform: { value in
            splitString = splitTextIntoLines(text: contentString, fontSize: fontSize)
        })
    }
    
    func splitTextIntoLines(text: String, fontSize: CGFloat) -> String {
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = 6
        paragraphStyle.lineBreakStrategy = .pushOut
        // Create NSTextStorage and specify the font size
        let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: fontSize), .paragraphStyle: paragraphStyle]
        let textStorage = NSTextStorage(string: text, attributes: attributes)
        let layoutManager = NSLayoutManager()
        textStorage.addLayoutManager(layoutManager)
        
        // Create an NSTextContainer of specified size
        let textContainer = NSTextContainer(size: containerSize)
        textContainer.maximumNumberOfLines = 0 // Indicates no maximum number of lines
        textContainer.lineBreakMode = .byCharWrapping // Set line breaking mode to character wrapping
        textContainer.lineFragmentPadding = 0.1
        layoutManager.addTextContainer(textContainer)
        layoutManager.ensureLayout(for: textContainer)
        
        // Return the split text lines
        var lines: [String] = [] // Store each split text line
        
        // Traverse the text within the display range
        layoutManager.enumerateLineFragments(forGlyphRange: NSRange(location: 0, length: layoutManager.numberOfGlyphs)) { _, usedRect, _, glyphRange, stop in
            
            if !usedRect.isEmpty {
                // Get the single line text
                let characterRange = Range(glyphRange, in: text)
                if let characterRange = characterRange {
                    // Retrieve line text from original text and add to lines array
                    let line = String(text[characterRange])
                    lines.append(line)
                    print("Split line: (line)")
                }
            } else {
                stop.pointee = true
            }
        }
        
        return lines.joined(separator: "")
    }
}

#Preview {
    SplitTextDemo()
}

  1. I adjusted the lineFragmentPadding in NSLayoutManager to match the padding of the UI components, which had no impact on the line breaking issue.

  2. I switched NSLayoutManager.lineBreakMode to byCharWrapping in an attempt to force character-by-character wrapping, but it did not affect the issue.

  3. I set paragraphStyle.lineBreakStrategy to .pushOut. This resolved the issue when phrases ended the sentence without full-width characters. However, the display still did not match TextKit’s segmentation when full-width characters were present.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật