Thanks, that almost solves all of my issues. On macOS, and when showing the text views directly in the iOS view hierarchy, using the page break character produces the expected result. For example with the string
(0..<1).map({ "\($0)" }).joined(separator: "\n") + String(UnicodeScalar(12)) + (0..<5).map({ "\($0)" }).joined(separator: "\n")
the view hierarchy looks like this:
But when printing them, the text views seem to overlap.
I'm afraid this is now a question for a printing expert. The code below produces both the view hierarchy and the print preview.
class ViewController: UIViewController {
override func viewDidAppear(_ animated: Bool) {
let printController = UIPrintInteractionController.shared
let printPageRenderer = PrintPageRenderer()
printController.printPageRenderer = printPageRenderer
printController.present(animated: true) { _, _, error in
if let error = error {
print(error.localizedDescription)
}
}
var y = 0.0
for textView in printPageRenderer.createTextViews.textViews {
textView.frame.origin = CGPoint(x: 0, y: y)
view.addSubview(textView)
y += textView.frame.height
}
}
}
class CreateTextViews: NSObject, NSLayoutManagerDelegate {
let pageSize: CGSize
let textStorage: NSTextStorage
private let layoutManager = NSLayoutManager()
private(set) var textViews = [UITextView]()
override init() {
pageSize = CGSize(width: 100, height: 100)
textStorage = NSTextStorage(string: (0..<1).map({ "\($0)" }).joined(separator: "\n") + String(UnicodeScalar(12)) + (0..<5).map({ "\($0)" }).joined(separator: "\n"), attributes: [.font: UIFont.systemFont(ofSize: 30)])
super.init()
layoutManager.delegate = self
textStorage.addLayoutManager(layoutManager)
if textStorage.length > 0 {
let glyphRange = layoutManager.glyphRange(forCharacterRange: NSRange(location: textStorage.length - 1, length: 0), actualCharacterRange: nil)
layoutManager.textContainer(forGlyphAt: glyphRange.location, effectiveRange: nil)
}
for textContainer in layoutManager.textContainers {
let textView = UITextView(frame: CGRect(origin: .zero, size: pageSize), textContainer: textContainer)
textViews.append(textView)
}
}
func layoutManager(_ layoutManager: NSLayoutManager, didCompleteLayoutFor textContainer: NSTextContainer?, atEnd layoutFinishedFlag: Bool) {
if textContainer == nil {
addPage()
}
}
private func addPage() {
let textContainer = NSTextContainer(size: pageSize)
layoutManager.addTextContainer(textContainer)
}
}
class PrintPageRenderer: UIPrintPageRenderer {
let createTextViews = CreateTextViews()
override var numberOfPages: Int {
if !Thread.isMainThread {
return DispatchQueue.main.sync { [self] in
numberOfPages
}
}
printFormatters = nil
var page = 0
for textView in createTextViews.textViews {
let printFormatter = textView.viewPrintFormatter()
printFormatter.maximumContentHeight = createTextViews.pageSize.height
addPrintFormatter(printFormatter, startingAtPageAt: page)
page += 1
}
return page
}
}
Topic:
UI Frameworks
SubTopic:
UIKit
Tags: