ParagraphStyleは、テキスト段落の視覚的な外観を定義する書式設定パラメータのセットです。モバイル開発において、ParagraphStyleには配置(left、center、right、justified)、行間隔、最初の行のインデント、段落間の間隔、テキストの方向が含まれます。Material Design Typography Guidelines(2025)によると、アプリケーションのすべての画面でParagraphStyleを一貫して使用することで、統一されたタイポグラフィックリズムが確保され、セクション間の切り替え時の視覚的なノイズが軽減されます。
重要なポイント
ParagraphStyle(段落スタイル)は、1つ以上のテキスト段落に適用可能な書式設定ルールの集合です。個々の文字レベルで機能する文字スタイル(bold、italic、font-size)とは異なり、ParagraphStyleはマクロプロパティを管理します:コンテナ内のテキスト配置、行間および段落間の間隔、書記方向、ハイフネーションルール。
歴史的に、ParagraphStyleの概念はデスクトップパブリッシングシステム(QuarkXPress、PageMaker、InDesign)から来ており、各段落に独自のパラメータセットがありました。モバイル開発では、このアプローチはソフトウェアAPIに変換されました:iOSのNSMutableParagraphStyle、AndroidのParagraphStyleおよびLineBreakStyleクラス、FlutterのtextAlignやtextHeightBehaviorなどのパラメータ。これらはすべて1つの目的を果たします — 段落書式の管理を、特定のテキストエンジンに縛られることなくコードを通じて行います。
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)は、NSMutableParagraphStyleを介してiOSでのみ完全にサポートされています。Androidでは、この目的のためにLeadingMarginSpanを使用したSpannableStringが使用され、FlutterではカスタムTextSpanとパディングを使用した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、またはNSParagraphStyleを属性を介してサポートするAttributedString(iOS 15+以降で利用可能)を使用する必要があります。
// 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はまた、改行の細かい制御のためのLineBreak(Simple、Heading、Paragraph)をサポートしており、これは多言語テキストに特に役立ちます。
// Jetpack Compose:TextStyleによるParagraphStyle
Text(
text = "カスタムスタイルの最初の段落。
インデント付きの2番目の段落。",
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でスタイル設定された段落。
インデント付きの2番目の段落。',
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は文字レベルで機能します。1つの段落に複数のTextStyleインスタンスが存在できますが、ParagraphStyleは段落ごとに1つだけです。
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アプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。