5

I am trying to achieve a multi page text editing layout, as in Pages, MS Word, ... . On OS X I can achieve this by creating one NSLayoutManager with one NSTextStorage for multiple NSTextViews. Each NSTextView has its own NSTextContainer. See below code for OS X. A simple example with text spreading between two NSTextViews:

import Cocoa

class ViewController: NSViewController {

let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage(attributedString: NSAttributedString(string: "This is a test"))
let textContainer1 = NSTextContainer()
let textContainer2 = NSTextContainer()

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.

    textStorage.addLayoutManager(layoutManager)

    textContainer1.widthTracksTextView = true
    textContainer1.heightTracksTextView = true
    textContainer2.widthTracksTextView = true
    textContainer2.heightTracksTextView = true

    let textView1 = NSTextView(frame: CGRectMake(0, 100, 100, 100), textContainer: textContainer1)
    textView1.backgroundColor = NSColor.greenColor()
    self.view.addSubview(textView1)
    layoutManager.addTextContainer(textContainer1)


    let textView2 = NSTextView(frame: CGRectMake(200, 100, 100, 100), textContainer: textContainer2)
    textView2.backgroundColor = NSColor.greenColor()
    self.view.addSubview(textView2)
    layoutManager.addTextContainer(textContainer2)
}
}

This works.

However, when I try to do the same on iOS with UITextView, the UITextViews become not selectable or editable. See my code for iOS:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {

let layoutManager = NSLayoutManager()
let textStorage = NSTextStorage(attributedString: NSAttributedString(string: "This is a test. This text should spread over two UITextViews. Bla bla bla bla bla bla bla bla bla bla bla bla bla"))
let textContainer1 = NSTextContainer()
let textContainer2 = NSTextContainer()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.        

    textStorage.addLayoutManager(layoutManager)

    textContainer1.heightTracksTextView = true
    textContainer1.widthTracksTextView = true
    textContainer2.heightTracksTextView = true
    textContainer2.widthTracksTextView = true

    let textView1 = UITextView(frame: CGRectMake(0, 100, 100, 100), textContainer: textContainer1)
    textView1.scrollEnabled = false
    textView1.delegate = self
    textView1.editable = true
    textView1.selectable = true
    textView1.backgroundColor = UIColor.greenColor()
    self.view.addSubview(textView1)
    layoutManager.addTextContainer(textContainer1)

    let textView2 = UITextView(frame: CGRectMake(200, 100, 100, 100), textContainer: textContainer2)
    textView2.scrollEnabled = false
    textView2.delegate = self
    textView2.editable = true
    textView2.selectable = true
    textView2.backgroundColor = UIColor.greenColor()
    self.view.addSubview(textView2)
    layoutManager.addTextContainer(textContainer2)

}
}

The text flows from one UITextView to the other, but it is not editable. I would be extremely thankful for any advice. I googled the issue and found other people experiencing the same problem, but found no solutions.

KnutKnatter
  • 61
  • 1
  • 2

2 Answers2

0

I've been searching for an answer too, and it seems that when a UITextView shares a layout manager with other text views, the text view unfortunately becomes static.

This issue is outlined in iOS 7 Programming Pushing the Limits: Develop Advance Applications for Apple, page 375:

Because you can easily add additional text containers to a layout manager, and because UITextView uses a layout manager, you may think it would be easy to create a multicolumn, editable UITextView. Unfortunately, this is not the case. If a UITextView is assigned multiple text containers [sic], it becomes static and cannot respond to user interaction such as editing or selection. This is a known issue and is currently "as designed".

Jeffrey Sun
  • 7,789
  • 1
  • 24
  • 17
  • I observed slightly different behavior. My scenario is 1 layoutmanager connected to N text containers. I spawn text view from these 0...N-1 text containers as I need it. I observe that 0th textview (first one) has selectable = true. All the rest I create have selectable = false, no matter if I remove the previous textviews from hierarchy. Quite baffling behavior, probably a bug by design. – Nirav Bhatt Aug 06 '19 at 17:42
0

My solution here which works is I keep an array of text that is rendered by layout manager for each text container and UITextView.

NOTE: These UITextViews should NOT be added to any parent views as subviews.

To acquire text for each text container and textview, use the code below.

let range = layoutManager.glyphRange(for: textContainer)
        let textViewText = (text as NSString).substring(with: range)
        strings.append(textViewText)

After acquiring all texts, create another set of textViews from the array of text and now add those textviews in scrollview or any parent view.

All the behavior of your text views will then work normally.

You can even use the UIPageViewController to render the text to have a beautiful swipe animation.

Zaldy Bughaw
  • 797
  • 8
  • 16