TextKit provides advanced text rendering and layout capabilities. Learn to create rich text experiences.
TextKit Setup
Basic Text Container
swift
import TextKit
import UIKit
class TextProcessor {
func createTextContainer(size: CGSize) -> NSTextContainer {
let container = NSTextContainer(size: size)
container.lineFragmentPadding = 0
container.maximumNumberOfLineFragments = 0
return container
}
func createLayoutManager() -> NSLayoutManager {
let layoutManager = NSLayoutManager()
layoutManager.usesFontLeading = false
return layoutManager
}
func createTextStorage() -> NSTextStorage {
let textStorage = NSTextStorage(string: "")
return textStorage
}
}Text Layout
Simple Text Layout
swift
class TextLayoutManager {
func layoutText(_ text: String, in container: NSTextContainer) {
let textStorage = NSTextStorage(string: text)
let layoutManager = NSLayoutManager()
layoutManager.addTextContainer(container)
textStorage.addLayoutManager(layoutManager)
let range = NSRange(location: 0, length: textStorage.length)
layoutManager_glyphRange(for: container)
layoutManager.setGlyphs(range)
}
}Attributed Text
swift
class AttributedTextManager {
func createAttributedText() -> NSAttributedString {
let text = "Hello, World!"
let attributedString = NSMutableAttributedString(string: text)
// Add attributes
attributedString.addAttribute(
.font,
value: UIFont.boldSystemFont(ofSize: 24),
range: NSRange(location: 0, length: 5)
)
attributedString.addAttribute(
.foregroundColor,
value: UIColor.blue,
range: NSRange(location: 7, length: 5)
)
return attributedString
}
func createRichText() -> NSAttributedString {
let text = """
Welcome to Swift
Advanced Text Processing
"""
let attributedString = NSMutableAttributedString(string: text)
// Apply different styles
let styles: [(range: NSRange, color: UIColor, font: UIFont)] = [
(
range: NSRange(location: 0, length: 7),
color: .blue,
font: UIFont.boldSystemFont(ofSize: 20)
),
(
range: NSRange(location: 8, length: 27),
color: .darkGray,
font: UIFont.systemFont(ofSize: 16)
)
]
for style in styles {
attributedString.addAttribute(.foregroundColor, value: style.color, range: style.range)
attributedString.addAttribute(.font, value: style.font, range: style.range)
}
return attributedString
}
}Text Rendering
Render to View
swift
class TextRenderer {
func renderTextToView(_ view: UIView, text: String) {
view.backgroundColor = .white
let textStorage = NSTextStorage(string: text)
let layoutManager = NSLayoutManager()
let container = NSTextContainer(size: view.bounds.size)
layoutManager.addTextContainer(container)
textStorage.addLayoutManager(layoutManager)
// Render
let graphicsContext = UIGraphicsGetCurrentContext()
container.draw(at: .zero, in: graphicsContext)
}
}Text Analysis
Text Attributes
swift
class TextAnalyzer {
func analyzeTextAttributes(_ attributedString: NSAttributedString) {
let range = NSRange(location: 0, length: attributedString.length)
// Enumerate attributes
attributedString.enumerateAttributes(in: range) { attributes, range, _ in
if let font = attributes[.font] as? UIFont {
print("Font: \(font.fontName), size: \(font.pointSize)")
}
if let color = attributes[.foregroundColor] as? UIColor {
print("Color: \(color)")
}
if let paragraphStyle = attributes[.paragraphStyle] as? NSParagraphStyle {
print("Paragraph style: \(paragraphStyle)")
}
}
}
func extractTextAttributes(at position: Int, from attributedString: NSAttributedString) -> [NSAttributedString.Key: Any] {
let range = NSRange(location: position, length: 1)
var attributes: [NSAttributedString.Key: Any] = [:]
attributedString.enumerateAttributes(in: range) { attrs, _, _ in
for (key, value) in attrs {
attributes[key] = value
}
}
return attributes
}
}Text Editing
Text Storage Management
swift
class TextEditorManager: NSObject, NSTextStorageDelegate {
var textStorage: NSTextStorage!
var layoutManager: NSLayoutManager!
var textContainer: NSTextContainer!
func setupEditor(in view: UIView) {
// Create text storage
textStorage = NSTextStorage(string: "")
textStorage.delegate = self
// Create layout manager
layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
// Create text container
textContainer = NSTextContainer(size: view.bounds.size)
layoutManager.addTextContainer(textContainer)
// Set up text view
let textView = UITextView(frame: view.bounds, textContainer: textContainer, layoutManager: layoutManager)
view.addSubview(textView)
}
func insertText(_ text: String, at range: NSRange) {
textStorage.replaceCharacters(in: range, with: text)
}
func applyAttributes(_ attributes: [NSAttributedString.Key: Any], to range: NSRange) {
textStorage.setAttributes(attributes, range: range)
}
}Text Calculation
Measure Text
swift
extension TextProcessor {
func measureText(_ text: String, constrainedTo size: CGSize, font: UIFont) -> CGRect {
let attributes: [NSAttributedString.Key: Any] = [.font: font]
let attributedString = NSAttributedString(string: text, attributes: attributes)
let framesetter = CTFramesetterCreateWithAttributedString(attributedString)
let path = CGPath(rect: CGRect(origin: .zero, size: size), transform: nil)
let bounds = CTFramesetterGetOptimizedBounds(framesetter, path, range: NSRange(location: 0, length: attributedString.length))
return bounds
}
func calculateHeight(for text: String, width: CGFloat, font: UIFont) -> CGFloat {
let size = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
let boundingRect = measureText(text, constrainedTo: size, font: font)
return ceil(boundingRect.height)
}
}Exclusion Paths
Text Around Shapes
swift
class ExclusionPathManager {
func createExclusionPath(in container: NSTextContainer, around rect: CGRect) {
let bezierPath = UIBezierPath(rect: rect)
container.exclusionPaths = [bezierPath]
}
func createCircularExclusion(in container: NSTextContainer, center: CGPoint, radius: CGFloat) {
let bezierPath = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: .pi * 2, clockwise: true)
container.exclusionPaths = [bezierPath]
}
func createImageExclusion(in container: NSTextContainer, around image: UIImage) {
// Create exclusion path around image
let imageSize = image.size
let imageRect = CGRect(
origin: .zero,
size: CGSize(width: imageSize.width + 20, height: imageSize.height + 20)
)
let bezierPath = UIBezierPath(roundedRect: imageRect, cornerRadius: 10)
container.exclusionPaths = [bezierPath]
}
}Text Selection
Custom Selection
swift
class TextSelectionManager {
func enableSelection(in view: UITextView) {
view.isSelectable = true
view.isEditable = false
view.textContainer.exclusionPaths = []
}
func getSelectedText(from view: UITextView) -> String? {
guard let range = view.selectedTextRange else {
return nil
}
return view.text(in: range)
}
func selectText(in view: UITextView, range: NSRange) {
view.selectedRange = range
}
}Best Practices
- 1Performance: Optimize for large texts
- 2Memory: Manage text storage efficiently
- 3Layout: Use appropriate layouts
- 4Attributes: Apply attributes efficiently
- 5Rendering: Render asynchronously when possible
- 6Accessibility: Support accessibility features
- 7Testing: Test with various text content
- 8Localization: Support right-to-left text
TextKit enables powerful text processing capabilities!