ParagraphStyle হল ফর্ম্যাটিং প্যারামিটারের একটি সেট যা টেক্সট প্যারাগ্রাফের ভিজ্যুয়াল চেহারা নির্ধারণ করে। মোবাইল ডেভেলপমেন্টে, ParagraphStyle-এর মধ্যে রয়েছে সারিবদ্ধকরণ (left, center, right, justified), লাইন স্পেসিং, প্রথম লাইনের ইন্ডেন্টেশন, প্যারাগ্রাফের মধ্যে স্পেসিং এবং টেক্সট দিক। Material Design Typography Guidelines (2025) অনুসারে, অ্যাপ্লিকেশনের সকল স্ক্রিনে ParagraphStyle-এর ধারাবাহিক ব্যবহার অভিন্ন টাইপোগ্রাফিক ছন্দ নিশ্চিত করে এবং সেকশনের মধ্যে স্যুইচ করার সময় ভিজ্যুয়াল শব্দ কমায়।
মূল পয়েন্ট
ParagraphStyle (প্যারাগ্রাফ স্টাইল) হল ফর্ম্যাটিং নিয়মের একটি সেট যা টেক্সটের এক বা একাধিক প্যারাগ্রাফে প্রয়োগযোগ্য। ক্যারেক্টার স্টাইল (bold, italic, font-size) থেকে ভিন্ন যা পৃথক ক্যারেক্টারের স্তরে কাজ করে, ParagraphStyle ম্যাক্রো-বৈশিষ্ট্য পরিচালনা করে: কন্টেইনারের মধ্যে টেক্সট অবস্থান, লাইন এবং প্যারাগ্রাফের মধ্যে স্পেসিং, লেখার দিক এবং হাইফেনেশন নিয়ম।
ঐতিহাসিকভাবে, ParagraphStyle-এর ধারণাটি ডেস্কটপ পাবলিশিং সিস্টেম (QuarkXPress, PageMaker, InDesign) থেকে এসেছে, যেখানে প্রতিটি প্যারাগ্রাফের নিজস্ব প্যারামিটারের সেট ছিল। মোবাইল ডেভেলপমেন্টে, এই পদ্ধতিটি সফ্টওয়্যার API-তে রূপান্তরিত হয়েছে: iOS-এ NSMutableParagraphStyle, Android-এ ParagraphStyle এবং LineBreakStyle ক্লাস, এবং Flutter-এ textAlign এবং textHeightBehavior-এর মতো প্যারামিটার। এগুলি সবই একটি উদ্দেশ্য পূরণ করে — প্যারাগ্রাফ ফর্ম্যাটিং পরিচালনা কোডের মাধ্যমে, কোনো নির্দিষ্ট টেক্সট ইঞ্জিনের সাথে আবদ্ধ না হয়ে।
Bringhurst — The Elements of Typographic Style (2024) অনুসারে, ParagraphStyle-এর সঠিক কনফিগারেশন ইন্টারফেস টাইপোগ্রাফিক সংস্কৃতির ভিত্তি। যদি টাইপফেস এবং ফন্ট সাইজ টেক্সটের «কণ্ঠস্বর» নির্ধারণ করে, তাহলে প্যারাগ্রাফ স্টাইল তার «শ্বাস» নির্ধারণ করে: ছন্দ, বিরতি এবং উচ্চারণ। মোবাইল ইন্টারফেসে যেখানে স্থান সীমিত, সঠিক ParagraphStyle পঠনযোগ্যতা না হারিয়ে আরও তথ্য ধারণ করতে দেয়।
ParagraphStyle-এ বৈশিষ্ট্যের বেশ কয়েকটি গ্রুপ অন্তর্ভুক্ত, প্রতিটি ফর্ম্যাটিংয়ের একটি নির্দিষ্ট দিকের জন্য দায়ী। আসুন মোবাইল API-তে উপলব্ধ মূল প্যারামিটারগুলি দেখি। সারিবদ্ধকরণ হল প্রধান প্যারামিটার যা টেক্সটের অনুভূমিক অবস্থান নির্ধারণ করে। 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-এ, এই উদ্দেশ্যে LeadingMarginSpan-সহ SpannableString ব্যবহার করা হয়, এবং Flutter-এ — কাস্টম TextSpan এবং padding-সহ RichText। ক্রস-প্ল্যাটফর্ম ডেভেলপমেন্টে (Flutter, React Native), কিছু ParagraphStyle বৈশিষ্ট্য কন্টেইনার বা Spacer-এর মাধ্যমে অনুকরণ করতে হয়।
iOS-এ, প্যারাগ্রাফ স্টাইলের সাথে কাজ করার প্রধান টুল হল NSMutableParagraphStyle ক্লাস — NSParagraphStyle-এর একটি সাবক্লাস। এটি প্যারাগ্রাফ ফর্ম্যাটিং পরিচালনার জন্য বৈশিষ্ট্যের একটি সম্পূর্ণ সেট প্রদান করে এবং NSAttributedString-এর মাধ্যমে প্রয়োগ করা হয়। NSMutableParagraphStyle শুধুমাত্র UILabel এবং UITextView-এ নয়, CTParagraphStyle-এর মাধ্যমে Core Text-এও ব্যবহৃত হয়।
// iOS: সম্পূর্ণ ParagraphStyle কনফিগারেশন
let paragraphStyle = NSMutableParagraphStyle()
// সারিবদ্ধকরণ
paragraphStyle.alignment = .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+ থেকে উপলব্ধ) ব্যবহার করতে হয়, যা অ্যাট্রিবিউটের মাধ্যমে NSParagraphStyle সমর্থন করে।
// SwiftUI: ParagraphStyle-সহ AttributedString (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 সিস্টেমে, প্যারাগ্রাফ প্যারামিটার TextView-এর XML অ্যাট্রিবিউট (android:textAlignment, android:lineSpacingExtra) বা android.text.style প্যাকেজ থেকে ParagraphStyle ইন্টারফেসের বাস্তবায়ন-সহ SpannableString-এর মাধ্যমে সেট করা হয়।
// Android View সিস্টেম: SpannableString-এর মাধ্যমে ParagraphStyle
val text = "First paragraph with settings.\n\nSecond paragraph."
val spannable = SpannableString(text)
// জাস্টিফাইড সারিবদ্ধকরণ
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 লাইন ব্রেক (Simple, Heading, Paragraph) এর সূক্ষ্ম নিয়ন্ত্রণের জন্য LineBreak-ও সমর্থন করে, যা বহুভাষিক টেক্সটের জন্য বিশেষভাবে উপযোগী।
// Jetpack Compose: TextStyle-এর মাধ্যমে ParagraphStyle
Text(
text = "কাস্টম স্টাইল-সহ প্রথম প্যারাগ্রাফ।
ইন্ডেন্ট-সহ দ্বিতীয় প্যারাগ্রাফ।",
style = TextStyle(
textAlign = TextAlign.Justify,
lineHeight = 24.sp,
textIndent = TextIndent(firstLine = 16.sp),
lineBreak = LineBreak.Paragraph
)
)
Android Developers — Compose ParagraphStyle (2025) অনুসারে, Compose-এ TextIndent ব্যবহার করার সময় firstLine sp-তে (dp-তে নয়) সেট করা গুরুত্বপূর্ণ, কারণ প্রথম লাইনের ইন্ডেন্ট টেক্সটের সাথে স্কেল করা উচিত। যদি ইন্ডেন্ট dp-তে সেট করা হয়, তাহলে ফন্ট সাইজ বাড়লে প্রথম লাইনের ইন্ডেন্ট দৃশ্যত ছোট হয়ে যাবে, যা টাইপোগ্রাফিক অনুপাত নষ্ট করবে।
Flutter-এ, ParagraphStyle প্রতিমানকে একটি ডেডিকেটেড ক্লাসে আলাদা করা হয়নি — পরিবর্তে TextStyle প্যারামিটার এবং অতিরিক্ত ক্লাসের সংমিশ্রণ ব্যবহার করা হয়। সারিবদ্ধকরণ TextAlign-এর মাধ্যমে, লাইন স্পেসিং height (এককবিহীন) এর মাধ্যমে সেট করা হয়, এবং TextHeightBehavior প্রথম এবং শেষ লাইনের দৃশ্যমান ইন্ডেন্ট নিয়ন্ত্রণ করে।
// Flutter: Text প্যারামিটারের মাধ্যমে ParagraphStyle
Text(
'Flutter-এ স্টাইল করা প্যারাগ্রাফ।
ইন্ডেন্ট-সহ দ্বিতীয় প্যারাগ্রাফ।',
style: TextStyle(
fontSize: 16,
height: 1.5,
leadingDistribution: TextLeadingDistribution.proportional,
),
textAlign: TextAlign.justify,
textHeightBehavior: TextHeightBehavior(
applyHeightToFirstAscent: true,
applyHeightToLastDescent: true,
),
)
আরও জটিল পরিস্থিতির জন্য, Flutter কাস্টম TextSpan এবং WidgetSpan-সহ RichText-এর ব্যবহার অফার করে। এটি অভিন্ন ফর্ম্যাটিং নিয়ম বজায় রেখে, একই প্যারাগ্রাফে ইনলাইন উইজেট (আইকন, ছবি) এর সাথে টেক্সট একত্রিত করার অনুমতি দেয়। তবে, এই পদ্ধতির জন্য লাইন ব্রেকের ম্যানুয়াল নিয়ন্ত্রণ প্রয়োজন এবং এটি স্বয়ংক্রিয় হাইফেনেশন সমর্থন করে না।
// 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 Flutter-এ ParagraphStyle-এর সঠিক প্রদর্শনের জন্য একটি মূল প্যারামিটার। যদি applyHeightToFirstAscent false-এ সেট করা হয়, তাহলে প্রথম লাইনের উপরের ইন্ডেন্ট উপেক্ষা করা হয়, এবং টেক্সট কন্টেইনারের উপরের সীমানায় «লেগে» যায়। এটি শিরোনামের জন্য উপযোগী, কিন্তু মূল টেক্সটের জন্য অবাঞ্ছিত।
ParagraphStyle-কে প্রতিটি লোকেলের জন্য লেখার দিক বিবেচনা করতে হবে। আরবি, হিব্রু বা উর্দু (ডান-থেকে-বাম লেখা, RTL) সমর্থন সহ মোবাইল অ্যাপে, ইন্ডেন্টেশন এবং সারিবদ্ধকরণ আয়নার মতো পরিবর্তন হওয়া উচিত। iOS baseWritingDirection = .natural-এর মাধ্যমে স্বয়ংক্রিয় সুইচিং সমর্থন করে, Android — TextDirection-এর মাধ্যমে, Flutter — textDirection-এর মাধ্যমে।
RTL লোকেলের জন্য সারিবদ্ধকরণ কনফিগারেশনের বিশেষ মনোযোগ প্রয়োজন। যদি LTR মোডে headIndent বাম ইন্ডেন্ট সেট করে, তাহলে RTL-এ এটি স্বয়ংক্রিয়ভাবে ডান ইন্ডেন্ট হয়ে যায়। তবে, সারিবদ্ধকরণ স্পষ্টভাবে নির্দিষ্ট করা হলে (NSTextAlignment.natural-এর পরিবর্তে NSTextAlignment.left) সব বাস্তবায়ন এই রূপান্তর সঠিকভাবে পরিচালনা করে না। Google Internationalization Guide (2025) অনুসারে, বহুভাষিক অ্যাপের জন্য সর্বদা প্রাকৃতিক সারিবদ্ধকরণ ব্যবহার করুন এবং উভয় লেআউটে ইন্ডেন্ট পরীক্ষা করুন।
// Android: ParagraphStyle-এ RTL সমর্থন
val textView = TextView(context)
// স্বয়ংক্রিয় RTL সমর্থন সক্ষম করুন
textView.textDirection = View.TEXT_DIRECTION_LOCALE
textView.textAlignment = View.TEXT_ALIGNMENT_TEXT_START
// RTL সমর্থন-সহ Spannable
val spannable = SpannableString(arabicText)
spannable.setSpan(
AlignmentSpan.Standard(Layout.Alignment.ALIGN_NORMAL),
0, arabicText.length,
Spannable.SPAN_PARAGRAPH
)
আঞ্চলিক বৈশিষ্ট্যগুলির মধ্যে প্রথম লাইন ইন্ডেন্টের জন্য বিভিন্ন নিয়মও অন্তর্ভুক্ত। ইউরোপীয় টাইপোগ্রাফিতে, প্রথম লাইন ইন্ডেন্ট (firstLineHeadIndent) প্যারাগ্রাফ পৃথকীকরণের জন্য একটি মানক। জাপানি এবং চীনা টাইপোগ্রাফিতে, প্রথম লাইন ইন্ডেন্টও ব্যবহার করা হয়, কিন্তু এর আকার ভিন্ন হতে পারে (সাধারণত ইউরোপীয় ঐতিহ্যে 1.5 em-এর তুলনায় 1 em)। আরবি টাইপোগ্রাফির জন্য, প্রথম লাইন ইন্ডেন্ট বিরল — প্যারাগ্রাফগুলি প্রায়শই উল্লম্ব স্পেসিং দ্বারা পৃথক করা হয়।
সবচেয়ে সাধারণ ভুল হল শুধুমাত্র গ্লোবাল টেক্সট ফিল্ড অ্যাট্রিবিউটের মাধ্যমে ParagraphStyle ব্যবহার করা পৃথক প্যারাগ্রাফের ভিন্ন ফর্ম্যাটিং বিবেচনা না করে। একটি UILabel বা TextView-তে একাধিক প্যারাগ্রাফ দ্বারা পৃথক করা, ParagraphStyle সম্পূর্ণ টেক্সটে একইভাবে প্রয়োগ করা হয়, যদি না প্রতিটি প্যারাগ্রাফের জন্য ভিন্ন স্টাইল-সহ অ্যাট্রিবিউটেড টেক্সট ব্যবহার করা হয়।
UX Collective — Common Typography Bugs in Mobile Apps (2025) অনুসারে, ParagraphStyle-এর সমস্যাগুলি মোবাইল অ্যাপ্লিকেশনে সমস্ত টাইপোগ্রাফিক বাগের 18% গঠন করে। সবচেয়ে গুরুত্বপূর্ণ ঘটনা হল যখন ভুল paragraphSpacing বিভিন্ন লাইনে টেক্সট ওভারল্যাপের দিকে নিয়ে যায় বা যখন RTL লোকেল LTR ইন্ডেন্ট-সহ প্রদর্শিত হয়। বিভিন্ন ভাষায় পরীক্ষা স্ট্রিং-সহ প্রতিটি ParagraphStyle প্যারামিটারের জন্য ইউনিট পরীক্ষা তৈরি করার সুপারিশ করা হয়।
প্রায়শই জিজ্ঞাসিত প্রশ্ন
NSMutableParagraphStyle প্যারাগ্রাফ ফর্ম্যাটিং (সারিবদ্ধকরণ, ইন্ডেন্টেশন, লাইন স্পেসিং) পরিচালনা করে, যখন TextStyle ক্যারেক্টার অ্যাট্রিবিউট (ফন্ট, রঙ, আকার) পরিচালনা করে। উভয়ই NSAttributedString-এর মাধ্যমে প্রয়োগ করা হয়। ParagraphStyle প্যারাগ্রাফ স্তরে কাজ করে, TextStyle ক্যারেক্টার স্তরে। একটি প্যারাগ্রাফে TextStyle-এর একাধিক উদাহরণ থাকতে পারে, কিন্তু প্রতি প্যারাগ্রাফে শুধুমাত্র একটি ParagraphStyle।
Jetpack Compose-এ, প্রথম লাইনের ইন্ডেন্ট TextStyle-এর ভিতরে TextIndent-এর মাধ্যমে সেট করা হয়: TextStyle(textIndent = TextIndent(firstLine = 16.sp))। মান sp-তে হওয়া উচিত যাতে এটি টেক্সটের সাথে স্কেল হয়। বহু-লাইন টেক্সটের জন্য, ইন্ডেন্ট প্রতিটি লাইনে প্রয়োগ করা হয় যা একটি নতুন প্যারাগ্রাফ ( ক্যারেক্টার) শুরু করে। প্রথম প্যারাগ্রাফের জন্য, ইন্ডেন্ট সর্বদা প্রয়োগ করা হয়।
SwiftUI-তে, paragraphSpacing-এর কোনো সরাসরি সমতুল্য নেই। প্যারাগ্রাফ স্পেসিংয়ের জন্য, NSMutableParagraphStyle এবং paragraphSpacing বৈশিষ্ট্য-সহ AttributedString (iOS 15+) ব্যবহার করুন। অথবা Text("...\n\n...")-এর মাধ্যমে প্যারাগ্রাফ আলাদা করুন এবং টেক্সট ব্লকের মধ্যে .padding() যোগ করুন। জটিল টাইপোগ্রাফিক পরিস্থিতির জন্য, UILabelRepresentable-এর মাধ্যমে NSAttributedString ব্যবহার করুন।
Android-এ TextView-তে paragraphSpacing বৈশিষ্ট্য নেই — এটি LeadingMarginSpan-সহ SpannableString-এর মাধ্যমে বা কাস্টম LineBackgroundSpan-এর মাধ্যমে সেট করা হয়। লাইন স্পেসিংয়ের জন্য setLineSpacing ব্যবহার করুন; প্যারাগ্রাফ স্পেসিংয়ের জন্য, অতিরিক্ত দিয়ে প্যারাগ্রাফ আলাদা করুন বা একাধিক TextView ইনস্ট্যান্সের সম্মিলিত কন্টেইনার ব্যবহার করুন।
সঠিক ParagraphStyle অ্যাক্সেসিবিলিটি উন্নত করে: পর্যাপ্ত paragraphSpacing জ্ঞানীয় প্রতিবন্ধী ব্যবহারকারীদের প্যারাগ্রাফ সীমানা আরও ভালভাবে চিহ্নিত করতে সহায়তা করে। WCAG 2.2 প্যারাগ্রাফের ভিজ্যুয়াল পৃথকীকরণ (ইন্ডেন্টেশন বা স্পেসিং) সুপারিশ করে। ParagraphSpacing 1.5 × line-height-এর কম হওয়া উচিত নয়। RTL লোকেলের জন্য, যাচাই করুন যে ইন্ডেন্টেশন সঠিকভাবে প্রতিফলিত হচ্ছে।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন