Instead of implementing a textview from scratch (UITextInput it a lot of work/boilerplate)
It makes sense for me to subclass UITextView.
However, when subclassing it seems this is limited to TextKit 1 only, I get an assertion failure:
*** Assertion failure in -[_UITextKit1LayoutController initWithTextView:textContainer:], _UITextKit1LayoutController.m:72
I thought I would just need to call the super init:
super.init(usingTextLayoutManager: true)
But this isn't a designated initialiser:
Must call a designated initializer of the superclass 'UITextView'
Is there a way to do this and override the layout manager so that it uses TextKit 2 in the subclass?
(My aim is to then draw the fragments manually using TextKit2 to get a custom layout while ultimately using all of the UITextView implementation as 99% of it is what I want - other than custom drawing of text fragments).
My code is below:
class DocumentTextView: UITextView {
private let _textLayoutManager = NSTextLayoutManager()
private var textContentStorage: NSTextContentStorage {
textLayoutManager!.textContentManager as! NSTextContentStorage
}
override var textLayoutManager: NSTextLayoutManager? {
_textLayoutManager
}
init() {
let textContainer = NSTextContainer(size: .zero)
super.init(frame: .zero, textContainer: textContainer)
_textLayoutManager.textContainer = textContainer
textContentStorage.attributedString = NSAttributedString(string: text, attributes: [
.foregroundColor: UIColor.label,
])
textContentStorage.addTextLayoutManager(_textLayoutManager)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Is there a way to do this and override the layout manager so that it uses TextKit 2 in the subclass?
To create a UITextView
subclass that uses TextKit2, you can use the designated initialer init(frame:textContainer:) directly, as shown below:
class MyTextView: UITextView { ... }
let textLayoutManager = NSTextLayoutManager()
let textContentStorage = NSTextContentStorage()
textContentStorage.addTextLayoutManager(textLayoutManager)
let size = CGSize(width: 200, height: 0) // The initial size.
let textContainer = NSTextContainer(size: )
textLayoutManager.textContainer = textContainer
let myTextView = MyTextView(frame: .zero, textContainer: textLayoutManager.textContainer)
My aim is to then draw the fragments manually using TextKit2 to get a custom layout while ultimately using all of the UITextView implementation as 99% of it is what I want - other than custom drawing of text fragments
I am unclear what you are trying to achieve, but when implementing custom drawing with UITextView
, people typically use their own text layout fragment (NSTextLayoutFragment) subclass + textLayoutManager(_:textLayoutFragmentFor:in:), rather than creating a UITextView
subclass.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.