简体   繁体   中英

NSLayoutManager with multiple NSTextContainers causes UITextViews to not be selectable/editable

I am trying to achieve a multi page text editing layout, as in Pages, MS Word, ... . On OS XI 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.

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".

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM