SubviewAttachingTextView
is a UITextView
subclass that allows embedding subviews in its attributed text as text attachments. The library also provides a SubviewAttachingTextViewBehavior
class that allows compositing the attachment behavior in existing UITextView
subclasses.
To see SubviewAttachingTextView
in action, clone or download this repository and check out Example.playground
inside SubviewAttachingTextView.xcworkspace
.
SubviewAttachingTextView
is built on top of NSTextAttachment
and Text Kit APIs available through UITextView
. A custom subclass of NSTextAttachment
allows keeping a reference to the embedded views, and text view's NSLayoutManager
and NSTextContainer
allow querying for the attachments' bounds as they're laid out inside the text, taking into account all paragraph style properties. NSLayoutManager
's and NSTextStorage
's delegate callbacks allow implementing automatic layout and attachment updates.
- Xcode 11.0+ (written in Swift 5.0).
- For compatibility with Swift 4.2, use version 1.4.0.
- For compatibility with Swift 4.0, use version 1.3.0.
- For compatibility with Swift 3.x, use version 1.2.2.
- iOS 8.0+
- Compatible with Objective-C.
-
Add the following line to your
Cartfile
:github "vlas-voloshin/SubviewAttachingTextView"
-
Follow the instructions outlined in Carthage documentation to build and integrate the library into your app.
-
Add the following line to your
Podfile
:pod 'SubviewAttachingTextView'
-
Execute
pod install
.
- Download and copy the repository source files into your project, or add it as a submodule to your git repository.
- Drag&drop
SubviewAttachingTextView.xcodeproj
into your project or workspace in Xcode. - In "General" tab of Project Settings →
Your Target
, you might find that Xcode has added a missing framework item in "Embedded Binaries". Delete it for now. - Still in "General" tab, add
SubviewAttachingTextView.framework
to "Embedded Binaries". This should also add it to "Linked Frameworks and Libraries".
There are two ways to integrate the subview attachment behavior in your text views; choose the one that fits your needs:
Simply change the class of UITextView
you use to SubviewAttachingTextView
(in Swift code) or VVSubviewAttachingTextView
(in Objective-C code and Interface Builder).
You can easily integrate SubviewAttachingTextViewBehavior
class into your custom UITextView
subclass by following the implementation of SubviewAttachingTextView
:
- In both
init(frame:, textContainer:)
andinit?(coder:)
initializers, create aSubviewAttachingTextViewBehavior
object (VVSubviewAttachingTextViewBehavior
in Objective-C), store it in your text view instance. - Assign your text view to the behavior's
textView
property. It's a weak property, so this won't create a retain cycle. - Assing the behavior object to the text view's
layoutManager.delegate
andtextStorage.delegate
. This will enable the automatic attachment management.- If your custom text view already needs a different object to be its layout manager's or text storage's delegate, you can manually proxy the calls to
layoutManager(_:, didCompleteLayoutFor:, atEnd:)
andtextStorage(_:, didProcessEditing:, range:, changeInLength:)
delegate methods, but keep in mind thatSubviewAttachingTextViewBehavior
might require more methods in future.
- If your custom text view already needs a different object to be its layout manager's or text storage's delegate, you can manually proxy the calls to
- Override the setter of
textContainerInset
property of your text view and make it calllayoutAttachedSubviews()
method of the attachment behavior. This ensures that the layout of attachments is updated when container insets are changed.
To embed a view in your text, do the following:
- Create a
SubviewTextAttachment
instance (VVSubviewTextAttachment
in Objective-C) and initialize it with a view object, optionally providing a size for the attachment.- If you don't provide a size explicitly, the attachment will attempt to use the view's fitting size (calculated using Auto Layout), falling back to the view's current size if a non-zero fitting size cannot be calculated.
- Alternatively, initialize the attachment with a view provider: an object conforming to
TextAttachedViewProvider
protocol (VVTextAttachedViewProvider
in Objective-C). Using a view provider allows rendering the attributed string with an attachment in multiple text views at the same time, with each text view receiving its own instance of a view representing the attachment from the view provider.TextAttachedViewProvider
also allows customizing the attached view's size during text layout. - Create an
NSAttributedString
from the attachment using itsinit(attachment:)
initializer. - Insert the resulting string into your attributed text and assign it on the text view (either
SubviewAttachingTextView
or your custom text view embedding aSubviewAttachingTextViewBehavior
). - Adding and removing the attached subviews is managed automatically. If you want to remove an embedded subview, just remove the corresponding attachment from the text view's attributed text.
- If your text view is editable, user will also be able to delete the attachment just like any other text.
- Using pasteboard operations (copy, cut, paste) with subview attachments in editable text views is not supported at the moment.
- Text layout is not automatically updated if the attached view's intrinsic size changes. At the moment, to change the size of an attached subview, the layout manager needs to be notified to invalidate layout and display for the corresponding character range, or the attachment needs to be removed from the text attributes and then added back.
This library is available under the MIT license. See the LICENSE
file for more info.