ParagraphStyle — concepte cheie, proprietăți și aplicare

Autor: IT Sectr Publicat: 2026-07-25 Timp de citire: 10 min

ParagraphStyle — este un set de parametri de formatare care definește aspectul vizual al unui paragraf de text. În dezvoltarea mobilă, ParagraphStyle include alinierea (left, center, right, justified), spațiile între rânduri, indentarea primei linii, spațiile între paragrafe și direcția textului. Conform Material Design Typography Guidelines (2025), utilizarea consecventă a ParagraphStyle pe toate ecranele aplicației asigură un ritm tipografic unitar și reduce zgomotul vizual la comutarea între secțiuni.

Principalele

  • ParagraphStyle — obiect de setări pentru formatarea paragrafului: aliniere, indentări, spații.
  • Platforme — iOS: NSMutableParagraphStyle, Android: ParagraphStyle (Compose) / Layout (View), Flutter: TextStyle.
  • Aliniere — left pentru text principal, center pentru titluri, justified pentru format carte.
  • Indentări — firstLineHeadIndent (indentare prima linie), paragraphSpacing (spațiu între paragrafe).
  • Localizare — ParagraphStyle ține cont de direcția textului (LTR/RTL) pentru diferite limbi.

Ce este ParagraphStyle în tipografie

ParagraphStyle (stilul paragrafului) — este un ansamblu de reguli de formatare aplicate unuia sau mai multor paragrafe de text. Spre deosebire de stilurile de caracter (bold, italic, font-size) care acționează la nivelul caracterelor individuale, ParagraphStyle gestionează macroproprietăți: amplasarea textului în container, distanțele între rânduri și paragrafe, direcția de scriere și regulile de întrerupere.

Din punct de vedere istoric, conceptul ParagraphStyle provine din sistemele de publicare desktop (QuarkXPress, PageMaker, InDesign), unde fiecare paragraf avea propriul set de parametri. În dezvoltarea mobilă, această abordare s-a transformat în API-uri programatice: NSMutableParagraphStyle pe iOS, clasele ParagraphStyle și LineBreakStyle în Android, precum și parametri precum textAlign și textHeightBehavior în Flutter. Toate rezolvă aceeași sarcină — gestionarea formatării paragrafelor prin cod, fără a fi legate de un motor text specific.

Conform Bringhurst — The Elements of Typographic Style (2024), configurarea corectă a ParagraphStyle stă la baza culturii tipografice a interfeței. Dacă fontul și dimensiunea răspund de „vocea" textului, stilul paragrafului răspunde de „respirația" acestuia: ritmul, pauzele și accentele. În interfețele mobile, unde spațiul este limitat, un ParagraphStyle adecvat permite includerea mai multor informații fără pierderea lizibilității.

Proprietățile principale ale ParagraphStyle

ParagraphStyle include mai multe grupuri de proprietăți, fiecare răspunzând pentru un aspect specific al formatării. Să examinăm parametrii cheie disponibili în API-urile mobile. Alinierea (alignment) — parametrul principal care determină poziția orizontală a textului. Pe iOS este disponibil NSTextAlignment, pe Android — Layout.Alignment, în Flutter — TextAlign.

ProprietateiOS (NSMutableParagraphStyle)Android (Compose)Flutter (TextStyle)
AlinierealignmenttextAligntextAlign
Indentare stângăheadIndenttextIndent (în Compose)
Indentare dreaptătailIndent
Indentare prima liniefirstLineHeadIndenttextIndent (firstLine)
Spațiu între paragrafeparagraphSpacingparagraphStyle (lineHeight)
Spațiu înainte de paragrafparagraphSpacingBefore
Direcția textuluibaseWritingDirectionTextDirection (Compose)textDirection
Mod de întrerupere rândlineBreakModeoverflow (TextStyle)overflow (TextStyle)

Este important de înțeles că nu toate proprietățile sunt disponibile pe toate platformele în aceeași măsură. De exemplu, indentarea primei linii (firstLineHeadIndent) este pe deplin suportată doar în iOS prin NSMutableParagraphStyle. În Android, în acest scop se utilizează SpannableString cu LeadingMarginSpan, iar în Flutter — RichText cu TextSpan personalizat și padding. În dezvoltarea cross-platform (Flutter, React Native) unele proprietăți ale ParagraphStyle trebuie emulate prin containere sau Spacer.

ParagraphStyle în iOS: NSMutableParagraphStyle

În iOS, instrumentul principal pentru lucrul cu stilul paragrafului este clasa NSMutableParagraphStyle — moștenită din NSParagraphStyle. Aceasta oferă un set complet de proprietăți pentru gestionarea formatării paragrafelor și se aplică prin NSAttributedString. NSMutableParagraphStyle este utilizat nu doar în UILabel și UITextView, ci și în Core Text prin CTParagraphStyle.

swift
// iOS: configurare completă ParagraphStyle
let paragraphStyle = NSMutableParagraphStyle()

// Aliniere
paragraphStyle.alignment = .justified     // justified

// Indentare
paragraphStyle.headIndent = 16          // indentare stângă
paragraphStyle.tailIndent = -16         // indentare dreaptă (negativă)
paragraphStyle.firstLineHeadIndent = 32 // indentare prima linie

// Spațiu între paragrafe
paragraphStyle.paragraphSpacing = 12    // după paragraf
paragraphStyle.paragraphSpacingBefore = 8 // înainte de paragraf

// Înălțime rând
paragraphStyle.minimumLineHeight = 24
paragraphStyle.maximumLineHeight = 24

let attributes: [NSAttributedString.Key: Any] = [
    .font: UIFont.systemFont(ofSize: 16),
    .paragraphStyle: paragraphStyle
]

let label = UILabel()
label.attributedText = NSAttributedString(
    string: "This paragraph has a custom ParagraphStyle.\n\nSecond paragraph with 12 pt spacing.",
    attributes: attributes
)

În SwiftUI nu există un echivalent direct al NSMutableParagraphStyle — în schimb se utilizează o combinație de modificatori: .multilineTextAlignment() pentru aliniere, .lineSpacing() pentru spațiu între rânduri. Pentru indentarea primei linii și spațiile între paragrafe în SwiftUI trebuie să se folosească Text + padding sau AttributedString (disponibil din iOS 15+).

swift
// SwiftUI: AttributedString cu ParagraphStyle (iOS 15+)
var attributed: AttributedString = """
This is the first paragraph with indent.

This is the second paragraph with 12 pt spacing.
"""

let ps = NSMutableParagraphStyle()
ps.paragraphSpacing = 12
ps.firstLineHeadIndent = 20

let container = AttributeContainer()
    .paragraphStyle(ps)

attributed.mergeAttributes(container)

Text(attributed)
    .font(.body)

Conform Apple — Text Programming Guide (2025), NSMutableParagraphStyle suportă până la 14 parametri diferiți de formatare. Este important de reținut că tailIndent se setează cu valoare negativă față de lățimea containerului, iar headIndent — cu valoare pozitivă. Acest comportament neevident duce adesea la erori la dezvoltatorii iOS începători.

ParagraphStyle în Android: View-system și Compose

În Android, abordarea față de ParagraphStyle diferă între View-system și Jetpack Compose. În View-system clasic, parametrii paragrafului se setează prin atributele XML ale TextView (android:textAlignment, android:lineSpacingExtra) sau prin SpannableString cu implementări ale interfeței ParagraphStyle din pachetul android.text.style.

kotlin
// Android View system: ParagraphStyle prin SpannableString
val text = "First paragraph with settings.\n\nSecond paragraph."
val spannable = SpannableString(text)

// Aliniere justified
spannable.setSpan(
    AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL),
    0, text.length,
    Spannable.SPAN_PARAGRAPH
)

// Indentare prima linie prin LeadingMarginSpan
spannable.setSpan(
    LeadingMarginSpan.Standard(0, 20),
    0, text.indexOf('\n'),
    Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)

textView.text = spannable

În Jetpack Compose, ParagraphStyle este gestionat prin parametrii TextStyle. Pentru aliniere se folosește textAlign, pentru spațiu între rânduri — lineHeight (în sp sau em), pentru indentarea primei linii — textIndent. Compose suportă de asemenea LineBreak pentru gestionarea fină a întreruperilor (Simple, Heading, Paragraph), util în special pentru text multilingv.

kotlin
// Jetpack Compose: ParagraphStyle prin TextStyle
Text(
    text = "Primul paragraf cu stil personalizat.\n\nAl doilea paragraf cu indentare.",
    style = TextStyle(
        textAlign = TextAlign.Justify,
        lineHeight = 24.sp,
        textIndent = TextIndent(firstLine = 16.sp),
        lineBreak = LineBreak.Paragraph
    )
)

Conform Android Developers — Compose ParagraphStyle (2025), când se utilizează TextIndent în Compose este important să se seteze firstLine în sp (nu în dp), deoarece indentarea primei linii trebuie să se scaleze împreună cu textul. Dacă indentarea se setează în dp, la mărirea dimensiunii fontului indentarea primei linii va deveni vizual mai mică, încălcând proporțiile tipografice.

ParagraphStyle în Flutter: TextHeightBehavior și StrutStyle

În Flutter, paradigma ParagraphStyle nu este separată într-o clasă dedicată — în schimb se utilizează o combinație de parametri TextStyle și clase suplimentare. Alinierea se setează prin TextAlign, spațiile între rânduri — prin height (fără unitate), iar TextHeightBehavior gestionează indentările vizibile ale primei și ultimei linii.

dart
// Flutter: ParagraphStyle prin parametrii Text
Text(
    'Paragraf stilizat în Flutter.\n\nAl doilea paragraf cu indentări.',
    style: TextStyle(
        fontSize: 16,
        height: 1.5,
        leadingDistribution: TextLeadingDistribution.proportional,
    ),
    textAlign: TextAlign.justify,
    textHeightBehavior: TextHeightBehavior(
        applyHeightToFirstAscent: true,
        applyHeightToLastDescent: true,
    ),
)

Pentru scenarii mai complexe, Flutter oferă utilizarea RichText cu TextSpan și WidgetSpan personalizate. Aceasta permite combinarea textului cu widgeturi inline (icoane, imagini) într-un singur paragraf, păstrând reguli unitare de formatare. Totuși, această abordare necesită gestionarea manuală a întreruperilor și nu suportă așezarea automată a întreruperilor.

dart
// Flutter: RichText cu formatare personalizată a paragrafului
RichText(
    text: TextSpan(
        style: TextStyle(fontSize: 16, height: 1.5),
        children: [
            TextSpan(text: 'First paragraph with icon '),
            WidgetSpan(
                child: Icon(Icons.star, size: 16),
                alignment: PlaceholderAlignment.middle,
            ),
            TextSpan(text: '\n\nSecond paragraph after spacing.'),
        ],
    ),
)

Conform Flutter Documentation — Text Widget (2025), TextHeightBehavior este parametrul cheie pentru afișarea corectă a ParagraphStyle în Flutter. Dacă applyHeightToFirstAscent este setat pe false, indentarea superioară a primei linii este ignorată, iar textul „se lipește" de marginea superioară a containerului. Acest lucru este util pentru titluri, dar nedorit pentru textul principal.

ParagraphStyle și localizarea: LTR/RTL și particularități regionale

ParagraphStyle trebuie să țină cont de direcția de scriere pentru fiecare localizare. În aplicațiile mobile cu suport pentru arabă, ebraică sau urdu (scriere de la dreapta la stânga, RTL), indentările și alinierea trebuie să se schimbe în oglindă. iOS suportă comutarea automată prin baseWritingDirection = .natural, Android — prin TextDirection, Flutter — prin textDirection.

Configurarea alinierii pentru localizările RTL necesită o atenție deosebită. Dacă în modul LTR headIndent setează indentarea stângă, în RTL aceasta devine automat dreaptă. Cu toate acestea, nu toate implementările gestionează corect această tranziție la setarea explicită a alinierii (NSTextAlignment.left în loc de NSTextAlignment.natural). Conform Google Internationalization Guide (2025), pentru aplicații multilingve folosește întotdeauna natural alignment și verifică indentările în ambele configurații.

kotlin
// Android: suport RTL în ParagraphStyle
val textView = TextView(context)

// Activează suportul automat RTL
textView.textDirection = View.TEXT_DIRECTION_LOCALE
textView.textAlignment = View.TEXT_ALIGNMENT_TEXT_START

// Spannable cu suport RTL
val spannable = SpannableString(arabicText)
spannable.setSpan(
    AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL),
    0, arabicText.length,
    Spannable.SPAN_PARAGRAPH
)

Particularitățile regionale includ de asemenea reguli diferite pentru indentarea primei linii. În tipografia europeană, indentarea primei linii (firstLineHeadIndent) este standardul pentru evidențierea paragrafelor. În tipografia japoneză și chineză, indentarea primei linii este de asemenea utilizată, dar dimensiunea sa poate diferi (de obicei 1 em față de 1.5 em în tradiția europeană). În tipografia arabă, indentarea primei linii este rară, paragrafele fiind mai des separate prin spațiu vertical.

Greșeli tipice la lucrul cu ParagraphStyle

Cea mai frecventă greșeală — utilizarea ParagraphStyle doar prin atributele globale ale câmpului text fără a ține cont de formatarea diferită a paragrafelor individuale. În UILabel sau TextView cu mai multe paragrafe separate prin \n, ParagraphStyle se aplică întregului text în mod egal, dacă nu se utilizează attributed-text cu stiluri diferite pentru fiecare paragraf.

  • Ignorarea paragraphSpacingBefore — mulți dezvoltatori setează paragraphSpacing, dar uită de paragraphSpacingBefore. Pentru primul paragraf dintr-un bloc, paragraphSpacingBefore permite setarea unui spațiu de sus fără a crea un container suplimentar. Acest lucru este util în special pentru liste cu titluri.
  • Aliniere rigidă (left/right) în loc de natural — dacă aplicația suportă localizări RTL, utilizarea NSTextAlignment.left sau TextAlign.Start în loc de natural duce la afișarea incorectă în localizările arabă și ebraică.
  • Lipsa verificării întreruperii rândurilor (line break mode) — în containere înguste (liste, sidebar), un lineBreakMode incorect duce la tăierea cuvintelor. Folosește byWordWrapping și verifică cuvintele lungi în contextul localizării specifice.
  • Amestecarea Spannable cu diferite ParagraphStyle — la setarea Spannable cu SPAN_PARAGRAPH este important să se calculeze corect limitele paragrafelor. Neconcordanța poziției de început/sfârșit cu limitele reale ale paragrafului duce la ignorarea stilului.
  • Alinierea baseline uitată — când se utilizează ParagraphStyle cu lineHeight fix (minimumLineHeight), asigură-te că alinierea textului la baseline este activată. În iOS, pentru aceasta se folosește label.baselineAdjustment = .alignBaselines.

Conform UX Collective — Common Typography Bugs in Mobile Apps (2025), problemele cu ParagraphStyle constituie 18% din toate bug-urile tipografice în aplicațiile mobile. Cele mai critice sunt cazurile când paragraphSpacing incorect duce la suprapunerea textului pe rânduri diferite sau când localizările RTL se afișează cu indentări LTR. Se recomandă crearea de teste unitare pentru fiecare parametru ParagraphStyle cu șiruri de test în diferite limbi.

Întrebări frecvente

Cu ce se deosebește ParagraphStyle de TextStyle în iOS?

NSMutableParagraphStyle gestionează formatarea paragrafelor (aliniere, indentări, spații între rânduri), iar TextStyle — atributele de caracter (font, culoare, dimensiune). Ambele se aplică prin NSAttributedString. ParagraphStyle acționează la nivel de paragraf, TextStyle — la nivel de caractere. Mai multe TextStyle pot fi într-un paragraf, dar ParagraphStyle — doar unul pe paragraf.

Cum se setează indentarea primei linii în Jetpack Compose?

În Jetpack Compose, indentarea primei linii se setează prin TextIndent în interiorul TextStyle: TextStyle(textIndent = TextIndent(firstLine = 16.sp)). Valoarea trebuie să fie în sp pentru a se scala cu textul. Pentru textul pe mai multe rânduri, indentarea se aplică fiecărui rând care începe un nou paragraf (caracterul \n). Pentru primul paragraf, indentarea se aplică întotdeauna.

Cum se configurează spațiul între paragrafe în SwiftUI?

În SwiftUI nu există un echivalent direct pentru paragraphSpacing. Pentru spațiul între paragrafe folosește AttributedString (iOS 15+) cu NSMutableParagraphStyle și proprietatea paragraphSpacing. Sau separă paragrafele prin Text("...\n\n...") și adaugă .padding() între blocurile de text. Pentru scenarii tipografice complexe, folosește NSAttributedString prin UILabelRepresentable.

De ce paragraphSpacing nu funcționează în Android TextView?

TextView în Android nu are proprietatea paragraphSpacing — aceasta se setează prin SpannableString cu LeadingMarginSpan sau prin LineBackgroundSpan personalizat. Pentru spațiul între rânduri folosește setLineSpacing, pentru spațiul între paragrafe — separă paragrafele cu \n suplimentar sau folosește un container compozit din mai multe TextView.

Cum influențează ParagraphStyle accesibilitatea aplicației mobile?

Un ParagraphStyle corect îmbunătățește accesibilitatea: un paragraphSpacing adecvat ajută utilizatorii cu dizabilități cognitive să distingă mai bine limitele paragrafelor. WCAG 2.2 recomandă separarea vizuală a paragrafelor (indentare sau spațiu). paragraphSpacing nu trebuie să fie mai mic de 1.5 × line-height. Pentru localizările RTL, verifică dacă indentările se afișează în oglindă.

Rezumat

  • ParagraphStyle — set de reguli de formatare a paragrafului: aliniere, indentări, spații între rânduri și paragrafe.
  • iOS — NSMutableParagraphStyle cu 14+ parametri, aplicat prin NSAttributedString; în SwiftUI — AttributedString (iOS 15+).
  • Android View — SpannableString cu implementări ParagraphStyle (AlignmentSpan, LeadingMarginSpan).
  • Android Compose — TextStyle.textAlign, lineHeight, textIndent și LineBreak pentru gestionarea întreruperilor.
  • Flutter — combinație de TextStyle.height, TextAlign, TextHeightBehavior și StrutStyle pentru fixarea înălțimii rândului.
  • Localizare — folosește natural alignment pentru suportul localizărilor RTL; verifică indentările în ambele configurații.
  • Greșeli tipice — aliniere rigidă în loc de natural, lipsa paragraphSpacingBefore, lineBreakMode incorect pentru containere înguste.

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.

Discutați proiectul

Citiți și