ParagraphStyle — adalah kumpulan parameter pemformatan yang menentukan tampilan visual paragraf teks. Dalam pengembangan mobile, ParagraphStyle mencakup perataan (left, center, right, justified), spasi antar baris, indentasi baris pertama, spasi antar paragraf, dan arah teks. Menurut Material Design Typography Guidelines (2025), penggunaan ParagraphStyle yang konsisten di semua layar aplikasi memastikan ritme tipografi yang seragam dan mengurangi kebisingan visual saat berpindah antar bagian.
Poin Utama
ParagraphStyle (gaya paragraf) — adalah kumpulan aturan pemformatan yang diterapkan pada satu atau beberapa paragraf teks. Berbeda dengan gaya karakter (bold, italic, font-size) yang bekerja pada tingkat karakter individual, ParagraphStyle mengelola properti makro: penempatan teks dalam wadah, jarak antar baris dan paragraf, arah penulisan, dan aturan pemutusan.
Secara historis, konsep ParagraphStyle berasal dari sistem penerbitan desktop (QuarkXPress, PageMaker, InDesign), di mana setiap paragraf memiliki kumpulan parameter sendiri. Dalam pengembangan mobile, pendekatan ini bertransformasi menjadi API pemrograman: NSMutableParagraphStyle di iOS, kelas ParagraphStyle dan LineBreakStyle di Android, serta parameter seperti textAlign dan textHeightBehavior di Flutter. Semuanya menyelesaikan tugas yang sama — pengelolaan pemformatan paragraf melalui kode, tanpa terikat pada mesin teks tertentu.
Menurut Bringhurst — The Elements of Typographic Style (2024), konfigurasi ParagraphStyle yang benar adalah dasar budaya tipografi antarmuka. Jika jenis huruf dan ukuran bertanggung jawab atas „suara" teks, maka gaya paragraf bertanggung jawab atas „napasnya": ritme, jeda, dan aksen. Dalam antarmuka mobile, di mana ruang terbatas, ParagraphStyle yang tepat memungkinkan menempatkan lebih banyak informasi tanpa kehilangan keterbacaan.
ParagraphStyle mencakup beberapa kelompok properti, yang masing-masing bertanggung jawab atas aspek pemformatan tertentu. Mari kita bahas parameter kunci yang tersedia di API mobile. Perataan (alignment) — parameter utama yang menentukan posisi horizontal teks. Di iOS tersedia NSTextAlignment, di Android — Layout.Alignment, di Flutter — TextAlign.
| Properti | iOS (NSMutableParagraphStyle) | Android (Compose) | Flutter (TextStyle) |
|---|---|---|---|
| Perataan | alignment | textAlign | textAlign |
| Indentasi kiri | headIndent | textIndent (di Compose) | — |
| Indentasi kanan | tailIndent | — | — |
| Indentasi baris pertama | firstLineHeadIndent | textIndent (firstLine) | — |
| Spasi antar paragraf | paragraphSpacing | paragraphStyle (lineHeight) | — |
| Spasi sebelum paragraf | paragraphSpacingBefore | — | — |
| Arah teks | baseWritingDirection | TextDirection (Compose) | textDirection |
| Mode pemutusan baris | lineBreakMode | overflow (TextStyle) | overflow (TextStyle) |
Penting untuk dipahami bahwa tidak semua properti tersedia di semua platform dalam jumlah yang sama. Misalnya, indentasi baris pertama (firstLineHeadIndent) didukung penuh hanya di iOS melalui NSMutableParagraphStyle. Di Android untuk tujuan ini digunakan SpannableString dengan LeadingMarginSpan, dan di Flutter — RichText dengan TextSpan kustom dan padding. Dalam pengembangan lintas platform (Flutter, React Native) beberapa properti ParagraphStyle harus diemulasi melalui wadah atau Spacer.
Di iOS, alat utama untuk bekerja dengan gaya paragraf adalah kelas NSMutableParagraphStyle — turunan dari NSParagraphStyle. Ia menyediakan serangkaian properti lengkap untuk mengelola pemformatan paragraf dan diterapkan melalui NSAttributedString. NSMutableParagraphStyle tidak hanya digunakan di UILabel dan UITextView, tetapi juga di Core Text melalui CTParagraphStyle.
// iOS: konfigurasi ParagraphStyle lengkap
let paragraphStyle = NSMutableParagraphStyle()
// Perataan
paragraphStyle.alignment = .justified // justified
// Indentasi
paragraphStyle.headIndent = 16 // indentasi kiri
paragraphStyle.tailIndent = -16 // indentasi kanan (negatif)
paragraphStyle.firstLineHeadIndent = 32 // indentasi baris pertama
// Spasi paragraf
paragraphStyle.paragraphSpacing = 12 // setelah paragraf
paragraphStyle.paragraphSpacingBefore = 8 // sebelum paragraf
// Tinggi baris
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
)
Di SwiftUI tidak ada padanan langsung NSMutableParagraphStyle — sebagai gantinya digunakan kombinasi pengubah: .multilineTextAlignment() untuk perataan, .lineSpacing() untuk spasi baris. Untuk indentasi baris pertama dan spasi antar paragraf di SwiftUI harus menggunakan Text + padding atau AttributedString (tersedia dari iOS 15+).
// SwiftUI: AttributedString dengan 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)
Menurut Apple — Text Programming Guide (2025), NSMutableParagraphStyle mendukung hingga 14 parameter pemformatan berbeda. Penting untuk diingat bahwa tailIndent diatur sebagai nilai negatif terhadap lebar wadah, dan headIndent — sebagai positif. Perilaku yang tidak jelas ini sering menyebabkan kesalahan pada pengembang iOS pemula.
Di Android, pendekatan terhadap ParagraphStyle berbeda antara View-sistem dan Jetpack Compose. Dalam View-sistem klasik, parameter paragraf diatur melalui atribut XML TextView (android:textAlignment, android:lineSpacingExtra) atau melalui SpannableString dengan implementasi antarmuka ParagraphStyle dari paket android.text.style.
// Android View system: ParagraphStyle melalui SpannableString
val text = "First paragraph with settings.\n\nSecond paragraph."
val spannable = SpannableString(text)
// Perataan justified
spannable.setSpan(
AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL),
0, text.length,
Spannable.SPAN_PARAGRAPH
)
// Indentasi baris pertama melalui LeadingMarginSpan
spannable.setSpan(
LeadingMarginSpan.Standard(0, 20),
0, text.indexOf('\n'),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
textView.text = spannable
Di Jetpack Compose, ParagraphStyle dikelola melalui parameter TextStyle. Untuk perataan digunakan textAlign, untuk spasi baris — lineHeight (dalam sp atau em), untuk indentasi baris pertama — textIndent. Compose juga mendukung LineBreak untuk pengelolaan pemutusan yang halus (Simple, Heading, Paragraph), yang sangat berguna untuk teks multibahasa.
// Jetpack Compose: ParagraphStyle melalui TextStyle
Text(
text = "Paragraf pertama dengan gaya kustom.\n\nParagraf kedua dengan indentasi.",
style = TextStyle(
textAlign = TextAlign.Justify,
lineHeight = 24.sp,
textIndent = TextIndent(firstLine = 16.sp),
lineBreak = LineBreak.Paragraph
)
)
Menurut Android Developers — Compose ParagraphStyle (2025), saat menggunakan TextIndent di Compose penting untuk mengatur firstLine dalam sp (bukan dp), karena indentasi baris pertama harus diskalakan dengan teks. Jika indentasi diatur dalam dp, saat ukuran font ditingkatkan, indentasi baris pertama akan menjadi lebih kecil secara visual, yang melanggar proporsi tipografi.
Di Flutter, paradigma ParagraphStyle tidak dipisahkan ke dalam kelas terpisah — sebagai gantinya digunakan kombinasi parameter TextStyle dan kelas tambahan. Perataan diatur melalui TextAlign, spasi baris — melalui height (tanpa unit), dan TextHeightBehavior mengelola indentasi baris pertama dan terakhir yang terlihat.
// Flutter: ParagraphStyle melalui parameter Text
Text(
'Paragraf bergaya di Flutter.\n\nParagraf kedua dengan indentasi.',
style: TextStyle(
fontSize: 16,
height: 1.5,
leadingDistribution: TextLeadingDistribution.proportional,
),
textAlign: TextAlign.justify,
textHeightBehavior: TextHeightBehavior(
applyHeightToFirstAscent: true,
applyHeightToLastDescent: true,
),
)
Untuk skenario yang lebih kompleks, Flutter menawarkan penggunaan RichText dengan TextSpan dan WidgetSpan kustom. Ini memungkinkan menggabungkan teks dengan widget inline (ikon, gambar) dalam satu paragraf, mempertahankan aturan pemformatan yang seragam. Namun, pendekatan ini memerlukan pengelolaan pemutusan manual dan tidak mendukung pengaturan pemutusan otomatis.
// Flutter: RichText dengan pemformatan paragraf kustom
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.'),
],
),
)
Menurut Flutter Documentation — Text Widget (2025), TextHeightBehavior adalah parameter kunci untuk menampilkan ParagraphStyle dengan benar di Flutter. Jika applyHeightToFirstAscent diatur ke false, indentasi atas baris pertama diabaikan dan teks „menempel" ke tepi atas wadah. Ini berguna untuk judul, tetapi tidak diinginkan untuk teks utama.
ParagraphStyle harus memperhitungkan arah penulisan untuk setiap lokalisasi. Dalam aplikasi mobile dengan dukungan bahasa Arab, Ibrani, atau Urdu (tulisan kanan ke kiri, RTL), indentasi dan perataan harus berubah secara cermin. iOS mendukung peralihan otomatis melalui baseWritingDirection = .natural, Android — melalui TextDirection, Flutter — melalui textDirection.
Konfigurasi perataan untuk lokalisasi RTL memerlukan perhatian khusus. Jika dalam mode LTR headIndent mengatur indentasi kiri, dalam RTL secara otomatis menjadi kanan. Namun, tidak semua implementasi menangani transisi ini dengan benar saat pengaturan perataan eksplisit (NSTextAlignment.left alih-alih NSTextAlignment.natural). Menurut Google Internationalization Guide (2025), untuk aplikasi multibahasa selalu gunakan natural alignment dan periksa indentasi di kedua tata letak.
// Android: dukungan RTL di ParagraphStyle
val textView = TextView(context)
// Aktifkan dukungan RTL otomatis
textView.textDirection = View.TEXT_DIRECTION_LOCALE
textView.textAlignment = View.TEXT_ALIGNMENT_TEXT_START
// Spannable dengan dukungan RTL
val spannable = SpannableString(arabicText)
spannable.setSpan(
AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL),
0, arabicText.length,
Spannable.SPAN_PARAGRAPH
)
Fitur regional juga mencakup aturan berbeda untuk indentasi baris pertama. Dalam tipografi Eropa, indentasi baris pertama (firstLineHeadIndent) adalah standar untuk penandaan paragraf. Dalam tipografi Jepang dan Cina, indentasi baris pertama juga digunakan, tetapi ukurannya mungkin berbeda (biasanya 1 em dibandingkan 1.5 em dalam tradisi Eropa). Dalam tipografi Arab, indentasi baris pertama jarang digunakan, paragraf lebih sering dipisahkan dengan spasi vertikal.
Kesalahan paling umum — penggunaan ParagraphStyle hanya melalui atribut global bidang teks tanpa mempertimbangkan pemformatan berbeda dari paragraf individual. Di UILabel atau TextView dengan beberapa paragraf dipisahkan oleh \n, ParagraphStyle diterapkan ke seluruh teks secara merata, kecuali jika attributed-text dengan gaya berbeda untuk setiap paragraf digunakan.
Menurut UX Collective — Common Typography Bugs in Mobile Apps (2025), masalah dengan ParagraphStyle merupakan 18% dari semua bug tipografi di aplikasi mobile. Yang paling kritis adalah kasus ketika paragraphSpacing yang salah menyebabkan tumpang tindih teks pada baris berbeda atau ketika lokalisasi RTL ditampilkan dengan indentasi LTR. Disarankan untuk membuat unit test untuk setiap parameter ParagraphStyle dengan string uji dalam berbagai bahasa.
Pertanyaan Umum
NSMutableParagraphStyle mengelola pemformatan paragraf (perataan, indentasi, spasi baris), sedangkan TextStyle mengelola atribut karakter (font, warna, ukuran). Keduanya diterapkan melalui NSAttributedString. ParagraphStyle bekerja pada tingkat paragraf, TextStyle pada tingkat karakter. Beberapa TextStyle dapat berada dalam satu paragraf, tetapi ParagraphStyle — hanya satu per paragraf.
Di Jetpack Compose, indentasi baris pertama diatur melalui TextIndent di dalam TextStyle: TextStyle(textIndent = TextIndent(firstLine = 16.sp)). Nilai harus dalam sp agar dapat diskalakan dengan teks. Untuk teks multibaris, indentasi diterapkan pada setiap baris yang memulai paragraf baru (karakter \n). Untuk paragraf pertama, indentasi selalu diterapkan.
Di SwiftUI tidak ada padanan langsung paragraphSpacing. Untuk spasi antar paragraf gunakan AttributedString (iOS 15+) dengan NSMutableParagraphStyle dan properti paragraphSpacing. Atau pisahkan paragraf melalui Text("...\n\n...") dan tambahkan .padding() di antara blok teks. Untuk skenario tipografi kompleks, gunakan NSAttributedString melalui UILabelRepresentable.
TextView di Android tidak memiliki properti paragraphSpacing — diatur melalui SpannableString dengan LeadingMarginSpan atau LineBackgroundSpan kustom. Untuk spasi baris gunakan setLineSpacing, untuk spasi antar paragraf — pisahkan paragraf dengan \n tambahan atau gunakan wadah gabungan dari beberapa TextView.
ParagraphStyle yang benar meningkatkan aksesibilitas: paragraphSpacing yang cukup membantu pengguna dengan gangguan kognitif untuk lebih membedakan batas paragraf. WCAG 2.2 merekomendasikan pemisahan visual paragraf (indentasi atau spasi). paragraphSpacing tidak boleh kurang dari 1.5 × line-height. Untuk lokalisasi RTL, periksa apakah indentasi ditampilkan secara cermin.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga