ParagraphStyle — είναι ένα σύνολο παραμέτρων μορφοποίησης που καθορίζει την οπτική εμφάνιση μιας παραγράφου κειμένου. Στην ανάπτυξη εφαρμογών για κινητά, το ParagraphStyle περιλαμβάνει στοίχιση (left, center, right, justified), διάστιχο, εσοχή πρώτης γραμμής, αποστάσεις μεταξύ παραγράφων και κατεύθυνση κειμένου. Σύμφωνα με τις Material Design Typography Guidelines (2025), η συνεπής χρήση του ParagraphStyle σε όλες τις οθόνες της εφαρμογής εξασφαλίζει έναν ενιαίο τυπογραφικό ρυθμό και μειώνει τον οπτικό θόρυβο κατά την εναλλαγή μεταξύ ενοτήτων.
Κύρια Σημεία
ParagraphStyle (στυλ παραγράφου) — είναι ένα σύνολο κανόνων μορφοποίησης που εφαρμόζονται σε μία ή περισσότερες παραγράφους κειμένου. Σε αντίθεση με τα στυλ χαρακτήρων (bold, italic, font-size) που λειτουργούν σε επίπεδο μεμονωμένων χαρακτήρων, το ParagraphStyle διαχειρίζεται μακρο-ιδιότητες: τοποθέτηση κειμένου στο δοχείο, αποστάσεις μεταξύ γραμμών και παραγράφων, κατεύθυνση γραφής και κανόνες διακοπής.
Ιστορικά, η έννοια του ParagraphStyle προέρχεται από συστήματα επιτραπέζιας έκδοσης (QuarkXPress, PageMaker, InDesign), όπου κάθε παράγραφος είχε το δικό της σύνολο παραμέτρων. Στην ανάπτυξη εφαρμογών για κινητά, αυτή η προσέγγιση μετατράπηκε σε προγραμματιστικά API: NSMutableParagraphStyle στο iOS, κλάσεις ParagraphStyle και LineBreakStyle στο Android, καθώς και παράμετροι όπως textAlign και textHeightBehavior στο Flutter. Όλες λύνουν το ίδιο πρόβλημα — διαχείριση μορφοποίησης παραγράφου μέσω κώδικα, χωρίς σύνδεση σε συγκεκριμένη μηχανή κειμένου.
Σύμφωνα με το Bringhurst — The Elements of Typographic Style (2024), η σωστή διαμόρφωση του ParagraphStyle είναι η βάση της τυπογραφικής κουλτούρας της διεπαφής. Ενώ η γραμματοσειρά και το μέγεθος είναι υπεύθυνα για τη „φωνή" του κειμένου, το στυλ παραγράφου είναι υπεύθυνο για την „αναπνοή" του: ρυθμό, παύσεις και τονισμούς. Στις διεπαφές κινητών, όπου ο χώρος είναι περιορισμένος, το κατάλληλο ParagraphStyle επιτρέπει την τοποθέτηση περισσότερων πληροφοριών χωρίς απώλεια αναγνωσιμότητας.
ParagraphStyle περιλαμβάνει πολλές ομάδες ιδιοτήτων, καθεμία από τις οποίες είναι υπεύθυνη για μια συγκεκριμένη πτυχή της μορφοποίησης. Ας εξετάσουμε τις βασικές παραμέτρους που είναι διαθέσιμες στα κινητά API. Στοίχιση (alignment) — η κύρια παράμετρος που καθορίζει την οριζόντια θέση του κειμένου. Στο iOS είναι διαθέσιμο το NSTextAlignment, στο Android — Layout.Alignment, στο Flutter — TextAlign.
| Ιδιότητα | iOS (NSMutableParagraphStyle) | Android (Compose) | Flutter (TextStyle) |
|---|---|---|---|
| Στοίχιση | alignment | textAlign | textAlign |
| Αριστερή εσοχή | headIndent | textIndent (στο Compose) | — |
| Δεξιά εσοχή | tailIndent | — | — |
| Εσοχή πρώτης γραμμής | firstLineHeadIndent | textIndent (firstLine) | — |
| Απόσταση μεταξύ παραγράφων | paragraphSpacing | paragraphStyle (lineHeight) | — |
| Απόσταση πριν από παράγραφο | paragraphSpacingBefore | — | — |
| Κατεύθυνση κειμένου | baseWritingDirection | TextDirection (Compose) | textDirection |
| Λειτουργία διακοπής γραμμής | lineBreakMode | overflow (TextStyle) | overflow (TextStyle) |
Είναι σημαντικό να κατανοήσουμε ότι δεν είναι όλες οι ιδιότητες διαθέσιμες σε όλες τις πλατφόρμες στον ίδιο βαθμό. Για παράδειγμα, η εσοχή πρώτης γραμμής (firstLineHeadIndent) υποστηρίζεται πλήρως μόνο στο iOS μέσω NSMutableParagraphStyle. Στο Android για αυτόν τον σκοπό χρησιμοποιείται SpannableString με LeadingMarginSpan, και στο Flutter — RichText με προσαρμοσμένο TextSpan και padding. Στην ανάπτυξη μεταξύ πλατφορμών (Flutter, React Native) ορισμένες ιδιότητες του ParagraphStyle πρέπει να εξομοιωθούν μέσω δοχείων ή Spacer.
Στο iOS, το κύριο εργαλείο για εργασία με στυλ παραγράφου είναι η κλάση NSMutableParagraphStyle — υποκλάση της NSParagraphStyle. Παρέχει ένα πλήρες σύνολο ιδιοτήτων για τη διαχείριση της μορφοποίησης παραγράφου και εφαρμόζεται μέσω NSAttributedString. Το NSMutableParagraphStyle χρησιμοποιείται όχι μόνο σε UILabel και UITextView, αλλά και στο Core Text μέσω CTParagraphStyle.
// iOS: πλήρης διαμόρφωση ParagraphStyle
let paragraphStyle = NSMutableParagraphStyle()
// Στοίχιση
paragraphStyle.alignment = .justified // justified
// Εσοχή
paragraphStyle.headIndent = 16 // αριστερή εσοχή
paragraphStyle.tailIndent = -16 // δεξιά εσοχή (αρνητική)
paragraphStyle.firstLineHeadIndent = 32 // εσοχή πρώτης γραμμής
// Απόσταση παραγράφων
paragraphStyle.paragraphSpacing = 12 // μετά την παράγραφο
paragraphStyle.paragraphSpacingBefore = 8 // πριν την παράγραφο
// Ύψος γραμμής
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
)
Στο SwiftUI δεν υπάρχει άμεσο αντίστοιχο του NSMutableParagraphStyle — αντίθετα χρησιμοποιείται συνδυασμός τροποποιητών: .multilineTextAlignment() για στοίχιση, .lineSpacing() για διάστιχο. Για εσοχή πρώτης γραμμής και αποστάσεις μεταξύ παραγράφων στο SwiftUI πρέπει να χρησιμοποιηθεί Text + padding ή AttributedString (διαθέσιμο από iOS 15+).
// SwiftUI: AttributedString με 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)
Σύμφωνα με το Apple — Text Programming Guide (2025), το NSMutableParagraphStyle υποστηρίζει έως 14 διαφορετικές παραμέτρους μορφοποίησης. Είναι σημαντικό να θυμόμαστε ότι το tailIndent ορίζεται ως αρνητική τιμή σε σχέση με το πλάτος του δοχείου, ενώ το headIndent — ως θετική. Αυτή η μη προφανής συμπεριφορά συχνά οδηγεί σε λάθη από αρχάριους προγραμματιστές iOS.
Στο Android, η προσέγγιση στο ParagraphStyle διαφέρει μεταξύ του View-συστήματος και του Jetpack Compose. Στο κλασικό View-σύστημα, οι παράμετροι παραγράφου ορίζονται μέσω XML χαρακτηριστικών του TextView (android:textAlignment, android:lineSpacingExtra) ή μέσω SpannableString με υλοποιήσεις του interface ParagraphStyle από το πακέτο android.text.style.
// Android View σύστημα: ParagraphStyle μέσω SpannableString
val text = "First paragraph with settings.\n\nSecond paragraph."
val spannable = SpannableString(text)
// Στοίχιση justified
spannable.setSpan(
AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL),
0, text.length,
Spannable.SPAN_PARAGRAPH
)
// Εσοχή πρώτης γραμμής μέσω LeadingMarginSpan
spannable.setSpan(
LeadingMarginSpan.Standard(0, 20),
0, text.indexOf('\n'),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
Στο Jetpack Compose, το ParagraphStyle διαχειρίζεται μέσω παραμέτρων TextStyle. Για στοίχιση χρησιμοποιείται textAlign, για διάστιχο — lineHeight (σε sp ή em), για εσοχή πρώτης γραμμής — textIndent. Το Compose υποστηρίζει επίσης LineBreak για λεπτομερή διαχείριση διακοπών (Simple, Heading, Paragraph), που είναι ιδιαίτερα χρήσιμο για πολύγλωσσο κείμενο.
// Jetpack Compose: ParagraphStyle μέσω TextStyle
Text(
text = "Πρώτη παράγραφος με προσαρμοσμένο στυλ.\n\nΔεύτερη παράγραφος με εσοχή.",
style = TextStyle(
textAlign = TextAlign.Justify,
lineHeight = 24.sp,
textIndent = TextIndent(firstLine = 16.sp),
lineBreak = LineBreak.Paragraph
)
)
Σύμφωνα με το Android Developers — Compose ParagraphStyle (2025), κατά τη χρήση του TextIndent στο Compose είναι σημαντικό να ορίζεται το firstLine σε sp (όχι σε dp), επειδή η εσοχή πρώτης γραμμής πρέπει να κλιμακώνεται με το κείμενο. Αν η εσοχή οριστεί σε dp, κατά την αύξηση του μεγέθους γραμματοσειράς η εσοχή πρώτης γραμμής θα γίνει οπτικά μικρότερη, παραβιάζοντας τις τυπογραφικές αναλογίες.
Στο Flutter, το παράδειγμα του ParagraphStyle δεν είναι διαχωρισμένο σε ξεχωριστή κλάση — αντίθετα χρησιμοποιείται συνδυασμός παραμέτρων TextStyle και πρόσθετων κλάσεων. Η στοίχιση ορίζεται μέσω TextAlign, τα διάστιχα — μέσω height (χωρίς μονάδα), και το TextHeightBehavior διαχειρίζεται τις ορατές εσοχές της πρώτης και τελευταίας γραμμής.
// Flutter: ParagraphStyle μέσω παραμέτρων Text
Text(
'Στυλιζαρισμένη παράγραφος στο Flutter.\n\nΔεύτερη παράγραφος με εσοχές.',
style: TextStyle(
fontSize: 16,
height: 1.5,
leadingDistribution: TextLeadingDistribution.proportional,
),
textAlign: TextAlign.justify,
textHeightBehavior: TextHeightBehavior(
applyHeightToFirstAscent: true,
applyHeightToLastDescent: true,
),
)
Για πιο σύνθετα σενάρια, το Flutter προσφέρει τη χρήση RichText με προσαρμοσμένο TextSpan και WidgetSpan. Αυτό επιτρέπει τον συνδυασμό κειμένου με ενσωματωμένα widget (εικονίδια, εικόνες) σε μία παράγραφο, διατηρώντας ενιαίους κανόνες μορφοποίησης. Ωστόσο, αυτή η προσέγγιση απαιτεί χειροκίνητη διαχείριση διακοπών και δεν υποστηρίζει αυτόματη τοποθέτηση διακοπών.
// Flutter: RichText με προσαρμοσμένη μορφοποίηση παραγράφου
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.'),
],
),
)
Σύμφωνα με το Flutter Documentation — Text Widget (2025), το TextHeightBehavior είναι η βασική παράμετρος για τη σωστή εμφάνιση του ParagraphStyle στο Flutter. Αν το applyHeightToFirstAscent οριστεί σε false, η πάνω εσοχή της πρώτης γραμμής αγνοείται και το κείμενο „κολλάει" στην πάνω άκρη του δοχείου. Αυτό είναι χρήσιμο για επικεφαλίδες, αλλά ανεπιθύμητο για το κύριο κείμενο.
ParagraphStyle πρέπει να λαμβάνει υπόψη την κατεύθυνση γραφής για κάθε τοπικοποίηση. Σε εφαρμογές κινητών με υποστήριξη αραβικών, εβραϊκών ή ούρντου (γραφή από δεξιά προς αριστερά, RTL), οι εσοχές και η στοίχιση πρέπει να αλλάζουν κατοπτρικά. Το iOS υποστηρίζει αυτόματη εναλλαγή μέσω baseWritingDirection = .natural, το Android — μέσω TextDirection, το Flutter — μέσω textDirection.
Η διαμόρφωση στοίχισης για τοπικοποιήσεις RTL απαιτεί ιδιαίτερη προσοχή. Αν στη λειτουργία LTR το headIndent ορίζει αριστερή εσοχή, στο RTL γίνεται αυτόματα δεξιά. Ωστόσο, δεν υλοποιούν όλες οι υλοποιήσεις σωστά αυτή τη μετάβαση κατά τη ρητή ρύθμιση στοίχισης (NSTextAlignment.left αντί για NSTextAlignment.natural). Σύμφωνα με το Google Internationalization Guide (2025), για πολύγλωσσες εφαρμογές χρησιμοποιείτε πάντα natural alignment και ελέγχετε τις εσοχές και στις δύο διατάξεις.
// Android: υποστήριξη RTL στο ParagraphStyle
val textView = TextView(context)
// Ενεργοποίηση αυτόματης υποστήριξης RTL
textView.textDirection = View.TEXT_DIRECTION_LOCALE
textView.textAlignment = View.TEXT_ALIGNMENT_TEXT_START
// Spannable με υποστήριξη RTL
val spannable = SpannableString(arabicText)
spannable.setSpan(
AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL),
0, arabicText.length,
Spannable.SPAN_PARAGRAPH
)
Τα περιφερειακά χαρακτηριστικά περιλαμβάνουν επίσης διαφορετικούς κανόνες για την εσοχή πρώτης γραμμής. Στην ευρωπαϊκή τυπογραφία, η εσοχή πρώτης γραμμής (firstLineHeadIndent) είναι το πρότυπο για την επισήμανση παραγράφων. Στην ιαπωνική και κινεζική τυπογραφία, η εσοχή πρώτης γραμμής χρησιμοποιείται επίσης, αλλά το μέγεθός της μπορεί να διαφέρει (συνήθως 1 em έναντι 1.5 em στην ευρωπαϊκή παράδοση). Στην αραβική τυπογραφία, η εσοχή πρώτης γραμμής είναι σπάνια, οι παράγραφοι συχνότερα διαχωρίζονται με κατακόρυφο διάστημα.
Το πιο συνηθισμένο λάθος — χρήση του ParagraphStyle μόνο μέσω καθολικών χαρακτηριστικών του πεδίου κειμένου χωρίς να λαμβάνεται υπόψη η διαφορετική μορφοποίηση μεμονωμένων παραγράφων. Σε UILabel ή TextView με πολλές παραγράφους διαχωρισμένες με \n, το ParagraphStyle εφαρμόζεται σε ολόκληρο το κείμενο ομοιόμορφα, εκτός αν χρησιμοποιείται attributed-text με διαφορετικά στυλ για κάθε παράγραφο.
Σύμφωνα με το UX Collective — Common Typography Bugs in Mobile Apps (2025), τα προβλήματα με το ParagraphStyle αποτελούν το 18% όλων των τυπογραφικών σφαλμάτων σε εφαρμογές κινητών. Πιο κρίσιμες είναι οι περιπτώσεις όπου το εσφαλμένο paragraphSpacing οδηγεί σε επικάλυψη κειμένου σε διαφορετικές γραμμές ή όταν οι τοπικοποιήσεις RTL εμφανίζονται με εσοχές LTR. Συνιστάται η δημιουργία unit tests για κάθε παράμετρο ParagraphStyle με δοκιμαστικές συμβολοσειρές σε διαφορετικές γλώσσες.
Συχνές Ερωτήσεις
Το NSMutableParagraphStyle διαχειρίζεται τη μορφοποίηση παραγράφου (στοίχιση, εσοχές, διάστιχα), ενώ το TextStyle διαχειρίζεται χαρακτηριστικά χαρακτήρων (γραμματοσειρά, χρώμα, μέγεθος). Και τα δύο εφαρμόζονται μέσω NSAttributedString. Το ParagraphStyle λειτουργεί σε επίπεδο παραγράφου, το TextStyle σε επίπεδο χαρακτήρων. Πολλά TextStyle μπορούν να βρίσκονται σε μία παράγραφο, αλλά ParagraphStyle — μόνο ένα ανά παράγραφο.
Στο Jetpack Compose, η εσοχή πρώτης γραμμής ορίζεται μέσω TextIndent μέσα στο TextStyle: TextStyle(textIndent = TextIndent(firstLine = 16.sp)). Η τιμή πρέπει να είναι σε sp για να κλιμακώνεται με το κείμενο. Για πολύγραμμο κείμενο, η εσοχή εφαρμόζεται σε κάθε γραμμή που ξεκινά νέα παράγραφο (χαρακτήρας \n). Για την πρώτη παράγραφο, η εσοχή εφαρμόζεται πάντα.
Στο SwiftUI δεν υπάρχει άμεσο αντίστοιχο του paragraphSpacing. Για απόσταση μεταξύ παραγράφων χρησιμοποιήστε AttributedString (iOS 15+) με NSMutableParagraphStyle και την ιδιότητα paragraphSpacing. Ή διαχωρίστε παραγράφους μέσω Text("...\n\n...") και προσθέστε .padding() μεταξύ μπλοκ κειμένου. Για σύνθετα τυπογραφικά σενάρια, χρησιμοποιήστε NSAttributedString μέσω UILabelRepresentable.
Το TextView στο Android δεν έχει ιδιότητα paragraphSpacing — ορίζεται μέσω SpannableString με LeadingMarginSpan ή προσαρμοσμένο LineBackgroundSpan. Για διάστιχο χρησιμοποιήστε setLineSpacing, για απόσταση μεταξύ παραγράφων — διαχωρίστε παραγράφους με επιπλέον \n ή χρησιμοποιήστε σύνθετο δοχείο από πολλά TextView.
Το σωστό ParagraphStyle βελτιώνει την προσβασιμότητα: το επαρκές paragraphSpacing βοηθά χρήστες με γνωστικές δυσκολίες να διακρίνουν καλύτερα τα όρια παραγράφων. Το WCAG 2.2 συνιστά οπτικό διαχωρισμό παραγράφων (εσοχή ή διάστημα). Το paragraphSpacing δεν πρέπει να είναι μικρότερο από 1.5 × line-height. Για τοπικοποιήσεις RTL, ελέγξτε ότι οι εσοχές εμφανίζονται κατοπτρικά.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης