UITextView este o componentă text multi-linie UIKit, care moștenește UIScrollView și suportă editarea textului atribuit cu încorporarea linkurilor și imaginilor. Conform documentației Apple Developer (2025), UITextView oferă UITextViewDelegate cu callback-uri textViewDidChange, shouldInteractWithURL și shouldInteractWithTextAttachment pentru gestionarea interacțiunilor. Spre deosebire de UITextField, UITextView suportă derularea, stilurile text prin typingAttributes și dataDetectorTypes pentru detectarea automată a linkurilor, adreselor și datelor. Aceasta este componenta principală pentru afișarea conținutului și introducerea textului multi-linie în aplicațiile iOS.
Principalele
UITextView este o componentă UIKit destinată afișării și editării textului multi-linie. Spre deosebire de UILabel, UITextView suportă selectarea textului, editarea, derularea la depășirea dimensiunilor și textul atribuit. Fiind moștenitor al UIScrollView, UITextView activează automat derularea verticală și orizontală la depășirea conținutului — aceasta se configurează prin isScrollEnabled. Clasa suportă editarea prin proprietatea isEditable: setați false pentru modul doar citire. UITextView lucrează cu NSLayoutManager prin sistemul TextKit: NSTextStorage (stocarea textului atribuit) → NSLayoutManager (aranjarea rândurilor) → NSTextContainer (geometria zonei de text). Această arhitectură permite crearea de aspect personalizat cu înfășurarea textului în jurul imaginilor, text multi-coloană și machete text complexe. UITextView este utilizat pentru afișarea articolelor, descrierilor, logurilor, comentariilor și oricărui text multi-linie în iOS.
Diferența dintre UITextView și UITextField depășește cu mult numărul de rânduri. UITextField este un UIControl pe un singur rând cu suport pentru placeholder, left/right view și buton de ștergere. UITextView este un UIScrollView multi-linie cu sistem TextKit complet pentru text atribuit. UITextField nu suportă NSAttributedString la nivel de afișare (doar prin attributedText cu limitări), UITextView procesează NSAttributedString complet cu fonturi diferite, stiluri de paragraf și imagini încorporate. UITextField are buton de ștergere încorporat (clearButtonMode), UITextView nu are — necesită implementare personalizată. UITextView își schimbă automat dimensiunea după conținut (intrinsicContentSize), UITextView necesită gestionare manuală a înălțimii prin observarea contentSize sau constrângeri Auto Layout. UITextView suportă dataDetectorTypes (detectare automată a linkurilor), UITextField le suportă din iOS 16+. Pentru introducerea textului multi-linie (comentarii, note, mesaje) alegeți UITextView. Pentru câmpuri de formular (nume, email, parolă) utilizați UITextField.
| Capacitate | UITextView | UITextField |
|---|---|---|
| Rânduri | Multi-linie | Un singur rând |
| Placeholder | Nu (personalizat) | Încorporat |
| Atribute text | NSAttributedString complet | Limitat |
| Data Detectors | Suport complet | iOS 16+ |
| Imagini inline | Prin NSTextAttachment | Nu se suportă |
| Derulare | Încorporată (UIScrollView) | Nu |
| Left/Right View | Nu | Încorporate |
NSAttributedString este o capacitate fundamentală a UITextView, care îl diferențiază de UITextField și UILabel. Șirul atribuit permite setarea diferitelor fonturi, culori, spațieri între rânduri, aliniere și linkuri în cadrul aceluiași text. Proprietăți: textView.attributedText = attributedString. Atribute cheie NSAttributedString.Key: font (.systemFont, .boldSystemFont, UIFont personalizat), foregroundColor, backgroundColor, paragraphStyle (NSMutableParagraphStyle cu lineSpacing, alignment, lineBreakMode), link (URL pentru linkuri interactive), underlineStyle, strikethroughStyle, shadow, baselineOffset, kern (spațiere între caractere). Pentru a crea attributedString utilizați init(string:, attributes:) sau NSMutableAttributedString pentru adăugarea atributelor la diferite intervale. UITextView afișează automat linkurile (link attribute) ca interactive — la apăsare se apelează metoda delegată shouldInteractWithURL. Pentru resetarea atributelor pentru introducere nouă utilizați typingAttributes.
import UIKit
let textView = UITextView()
textView.isEditable = false
textView.isScrollEnabled = true
textView.dataDetectorTypes = [.link, .phoneNumber]
let attributedString = NSMutableAttributedString(
string: "Visit our website or call +1-800-555-0199"
)
attributedString.addAttributes([
.font: UIFont.systemFont(ofSize: 16),
.foregroundColor: UIColor.label,
], range: NSRange(location: 0, length: 11))
let linkRange = (attributedString.string as NSString)
.range(of: "website")
attributedString.addAttributes([
.link: URL(string: "https://example.com")!,
.foregroundColor: UIColor.systemBlue,
], range: linkRange)
textView.attributedText = attributedString
UITextViewDelegate este un protocol care gestionează editarea și interacțiunea cu textul. Metode principale: textViewDidBeginEditing(textView) — se apelează la începerea editării; textViewDidEndEditing — la finalizare; textViewDidChange — la fiecare modificare a textului; textViewDidChangeSelection — la modificarea selecției; textViewShouldInteractWithURL — la apăsarea unui link (returnează Bool, dacă navigarea este permisă); textViewShouldInteractWithTextAttachment — la apăsarea unei imagini încorporate. Pentru gestionarea linkurilor în interiorul UITextView suprascrieți shouldInteractWithURL — în el puteți: deschide URL în SFSafariViewController, afișa UIAlertController pentru confirmare, gestiona scheme URL personalizate. Important: dacă textView.isEditable = true, linkurile devin indisponibile pentru apăsare până la dublu tap — pentru linkuri interactive la editare utilizați gesture recognizers.
SFSafariViewController — metoda standard de deschidere a linkurilor în aplicațiile iOS. În metoda shouldInteractWithURL creați un SFSafariViewController cu URL și prezentați-l modal sau prin navigationController. Pentru linkuri universale utilizați UIApplication.shared.open(url, options) — dar aceasta iese din aplicație. Pentru a interzice deschiderea linkurilor returnați false în shouldInteractWithURL și gestionați URL-ul manual.
NSTextContainer — parte a arhitecturii TextKit, care definește zona geometrică în care este afișat textul UITextView. Fiecare UITextView are un textContainer standard, configurabil prin: textView.textContainerInset — marginile textului față de granițele textView (UIEdgeInsets); textView.textContainer.lineFragmentPadding — marginea orizontală în interiorul fiecărui rând; textView.textContainer.maximumNumberOfLines — limitarea numărului de rânduri (0 = fără limită); textView.textContainer.exclusionPaths — un array de UIBezierPath pentru zonele pe care textul trebuie să le ocolească (imagini, forme personalizate). ExclusionPaths permit crearea de aspect complex: textul înconjoară o imagine rotundă de profil, o pictogramă sau orice contur arbitrar. Pentru dimensiunea dinamică a UITextView observați contentSize prin KVO sau delegat și actualizați constrângerile.
// Înălțime dinamică UITextView prin contentSize
func textViewDidChange(textView: UITextView) {
let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(
CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude)
)
heightConstraint.constant = newSize.height
UIView.animate(withDuration: 0.1) {
self.view.layoutIfNeeded()
}
}
// ExclusionPath pentru înfășurarea imaginilor
let imageFrame = CGRect(x: 16, y: 100, width: 80, height: 80)
let exclusionPath = UIBezierPath(rect: imageFrame)
textView.textContainer.exclusionPaths = [exclusionPath]
dataDetectorTypes — proprietatea UITextView care recunoaște automat și face interactive anumite tipuri de date în text: .link (URL, email), .phoneNumber (numere de telefon), .address (adrese), .calendarEvent (date și evenimente), .flightNumber (numere de zbor), .lookupSuggestion (sugestii de căutare), .trackingNumber (numere de urmărire), .money (sume), .shipmentTrackingNumber, .all (toate tipurile). Data Detector lucrează cu NSDataDetector și URL, evidențiind automat datele detectate. Pentru personalizarea gestionării setați dataDetectorTypes și suprascrieți shouldInteractWithURL în delegat. Important: dataDetectorTypes funcționează doar pentru URL și phoneNumber fără configurare suplimentară — celelalte tipuri pot necesita iOS 16+. Data Detector nu intră în conflict cu link attribute în NSAttributedString — ambele mecanisme funcționează paralel. Pentru UITextView doar citire cu conținut (știri, articole) setați dataDetectorTypes = [.link, .phoneNumber].
Să examinăm două exemple practice de utilizare a UITextView în aplicațiile iOS. Primul — text view doar citire cu text atribuit și data detector pentru afișarea conținutului. Al doilea — text view editabil cu placeholder leneș și înălțime dinamică pentru formularul de comentarii. Ambele exemple utilizează best practices UIKit: protocolul delegat, Auto Layout și TextKit.
Modul doar citire se activează prin setarea isEditable = false și isSelectable = true. Aceasta permite utilizatorului să selecteze textul și să apese pe linkuri, dar nu să editeze. Setați dataDetectorTypes pentru detectarea automată a linkurilor, backgroundColor = .clear pentru fundal transparent. Pentru afișarea conținutului lung utilizați attributedText cu NSMutableParagraphStyle lineSpacing pentru lizibilitate. Adăugați link attributes pentru linkurile cheie din text.
import UIKit
class ArticleViewController: UIViewController {
let contentView = UITextView()
override func viewDidLoad() {
super.viewDidLoad()
contentView.isEditable = false
contentView.isSelectable = true
contentView.dataDetectorTypes = [.link, .phoneNumber]
contentView.backgroundColor = .clear
contentView.textContainerInset = UIEdgeInsets(
top: 8, left: 16,
bottom: 8, right: 16
)
contentView.delegate = self
loadArticleContent()
}
func loadArticleContent() {
guard let url = URL(string: "https://example.com/article")
else { return }
// Încarcă conținutul din URL și setează attributedText
}
}
Placeholder pentru UITextView nu este încorporat — implementați-l printr-un UILabel deasupra textView sau prin attributedText cu verificarea isEmpty. Abordare simplă: un UILabel cu text gri care se ascunde la începerea editării. În textViewDidChange verificați prezența textului și ascundeți/afișați placeholder-ul. Pentru o soluție mai elegantă utilizați proprietatea typingAttributes pentru a seta culoarea textului introdus. Înălțimea dinamică a textView se obține prin observarea contentSize și actualizarea constrângerilor — acesta este modelul standard pentru chat-uri și formulare de comentarii.
Întrebări frecvente
UITextView nu are placeholder încorporat. Soluția standard: adăugați un UILabel cu text gri deasupra textView. În textViewDidBeginEditing ascundeți label-ul, în textViewDidEndEditing afișați-l dacă textul este gol. Alternativ: utilizați attributedText cu culoare gri ca placeholder și resetați-l la începerea editării. Pentru o soluție gata făcută utilizați biblioteca KMPlaceholderTextView sau ReactorKit.
Setați textContainerInset = .zero și lineFragmentPadding = 0: textView.textContainerInset = UIEdgeInsets.zero; textView.textContainer.lineFragmentPadding = 0. Suplimentar: textView.contentInset = .zero. Aceasta va elimina complet marginile de la marginile textView până la text. Rețineți că lineFragmentPadding implicit este 5.
Verificați: isSelectable = true (necesar pentru interacțiune), dataDetectorTypes include .link, delegatul nu returnează false în shouldInteractWithURL. Dacă textView.isEditable = true, linkurile sunt indisponibile pentru o singură apăsare — este necesar dublu tap. Pentru linkuri interactive în textView editabil adăugați un UITapGestureRecognizer deasupra textView și gestionați URL-ul manual.
Setați isScrollEnabled = true și adăugați o constrângere de înălțime cu valoare fixă. Textul care depășește înălțimea va fi derulat. Pentru UX optim utilizați maxHeight: observați contentSize și setați constrângerea de înălțime nu mai mare de maxHeight. La depășirea maxHeight activați scrollEnabled. Acesta este modelul standard pentru câmpurile de introducere a mesajelor și comentariilor.
Utilizați NSTextAttachment: creați un obiect, setați image și bounds, apoi creați un NSAttributedString din attachment și inserați-l în textView.attributedText. Exemplu: let attachment = NSTextAttachment(); attachment.image = image; attachment.bounds = CGRect(x, y, width, height); let attributedString = NSAttributedString(attachment: attachment). Imaginea se va afișa inline în text și se va derula împreună cu acesta.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și