使用TextKit 2在UITextView中显示表格

问题描述 投票:0回答:1

UITextView
不支持任何类型的表格,但我正在尝试创建一个文本视图实现,它将能够在普通文本旁边显示表格。

基本上:在创建 PDF 时,我的 macOS 端口使用

NSTextTable
渲染一些彼此相邻的段落。我正在尝试想出一种方法在 iOS 上实现这一目标。

TextKit 2 的文档和实际实现仍然有点模糊,但我很感兴趣是否可以使用

NSTextElement
NSTextElementProvider
创建我自己的内容类型。如果我没读错的话,我会定义一个由我自己的实现/布局控制的范围?

由于文档非常稀疏,我非常不确定如何实际实现

NSTextElement
,它在保存为 PDF 时也会呈现为文本 - 或者这是否可能。

任何帮助或提示,我们将不胜感激。

ios swift uikit textkit
1个回答
0
投票

没有真正的方法可以解决实际问题,但您可以创建一个类似于表格的视图提供程序。

这个例子只支持一行,所以它基本上只是一个列视图,但你应该能够很容易地扩展它。如果您想要一个二维表格,调整单元格的大小将是最棘手的部分。

实际的文本附件,它注册一个视图提供程序来显示假表:

@objc public class TableAttachment:NSTextAttachment {
    // We need to forward these values to the provider when needed
    var cells:[TextTableCell]?
    var spacing = 0.0
    var margin = 0.0
    
    @objc public init(cells:[TextTableCell], spacing:CGFloat = 0.0, margin:CGFloat = 0.0) {
        NSTextAttachment.registerViewProviderClass(TextTableProvider.self, forFileType: "public.data")
        
        self.cells = cells
        self.spacing = spacing
        self.margin = margin
        
        super.init(data: nil, ofType: "public.data")
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}

充当表格单元格的标签:

@objc public class TextTableCell:UILabel {
    var width = 0.0
    
    @objc public init(content:NSAttributedString, width: Double, height:Double = 0.0) {
        self.width = width

        let rect = CGRect(x: 0.0, y: 0.0, width: width, height: height)
        super.init(frame: rect)
                
        self.attributedText = content
        
        self.lineBreakMode = .byWordWrapping
        self.numberOfLines = 50 // Arbitrary value

        // Make the text field behave correctly in a PDF        
        self.layer.shouldRasterize = false
    }

    var height:CGFloat {
        guard var attributedText = self.attributedText  else { return 0.0 }        
        // Calculate frame size
        let rect = attributedText.boundingRect(with: CGSize(width: self.frame.width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
        
        self.frame.size.height = rect.size.height
        self.frame.origin.y = 0
        
        return self.frame.height
    }
}

最后,文本附件提供程序,它接收一堆表格单元格并显示它们。

@objc public class TextTableProvider : NSTextAttachmentViewProvider {
    var cells:[TextTableCell] = []
    var spacing = 0.0
    var margin = 0.0
    
    override init(textAttachment: NSTextAttachment, parentView: UIView?, textLayoutManager: NSTextLayoutManager?, location: NSTextLocation) {
        
        if let attachment = textAttachment as? TableAttachment {
            self.cells = attachment.cells ?? []
            self.spacing = attachment.spacing
            self.margin = attachment.margin
        }
        
        super.init(textAttachment: textAttachment, parentView: parentView, textLayoutManager: textLayoutManager, location: location)
        tracksTextAttachmentViewBounds = true
    }
    
    @objc public override func loadView() {
        super.loadView()
        
        view = UIView()

        // Add subviews
        var x = self.margin
        for column in self.cells {
            column.frame.origin.x = x
            view?.addSubview(column)
            
            x = spacing + CGRectGetMaxX(column.frame)
        }
    }

    /// Returns height of the tallest column in this view
    @objc public override func attachmentBounds(
        for attributes: [NSAttributedString.Key : Any],
        location: NSTextLocation,
        textContainer: NSTextContainer?,
        proposedLineFragment: CGRect,
        position: CGPoint
    ) -> CGRect {
        var height = 0.0

        for column in self.cells {
            let colHeight = column.height 
            if colHeight > height { height = colHeight }
        }

        // I have no idea what this - 15.0 is, something for my own purposes, probably
        return CGRect(x: 0, y: 0, width: proposedLineFragment.width - 15.0, height: height)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.