ParagraphStyle — 핵심 개념, 속성 및 사용법

저자: IT Sectr 게시일: 2026-07-25 읽는 시간: 10 분

ParagraphStyle은 텍스트 단락의 시각적 모양을 정의하는 서식 매개변수 집합입니다. 모바일 개발에서 ParagraphStyle에는 정렬(left, center, right, justified), 줄 간격, 첫 줄 들여쓰기, 단락 간 간격 및 텍스트 방향이 포함됩니다. Material Design Typography Guidelines(2025)에 따르면, 애플리케이션의 모든 화면에서 ParagraphStyle을 일관되게 사용하면 통일된 타이포그래픽 리듬이 보장되고 섹션 간 전환 시 시각적 노이즈가 줄어듭니다.

핵심 요점

  • ParagraphStyle — 단락 서식 설정 객체: 정렬, 들여쓰기, 간격.
  • 플랫폼 — iOS: NSMutableParagraphStyle, Android: ParagraphStyle(Compose) / Layout(View), Flutter: TextStyle.
  • 정렬 — 본문 텍스트는 left, 제목은 center, 책 형식은 justified.
  • 들여쓰기 — firstLineHeadIndent(첫 줄 들여쓰기), paragraphSpacing(단락 간 간격).
  • 현지화 — ParagraphStyle은 다양한 언어의 텍스트 방향(LTR/RTL)을 고려합니다.

타이포그래피에서 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의 주요 속성

ParagraphStyle에는 각각 서식의 특정 측면을 담당하는 여러 속성 그룹이 포함됩니다. 모바일 API에서 사용 가능한 주요 매개변수를 살펴보겠습니다. 정렬은 텍스트의 수평 위치를 결정하는 기본 매개변수입니다. iOS에서는 NSTextAlignment, Android에서는 Layout.Alignment, Flutter에서는 TextAlign을 사용할 수 있습니다.

속성iOS(NSMutableParagraphStyle)Android(Compose)Flutter(TextStyle)
정렬alignmenttextAligntextAlign
왼쪽 들여쓰기headIndenttextIndent(Compose에서)
오른쪽 들여쓰기tailIndent
첫 줄 들여쓰기firstLineHeadIndenttextIndent(firstLine)
단락 간 간격paragraphSpacingparagraphStyle(lineHeight)
단락 전 간격paragraphSpacingBefore
텍스트 방향baseWritingDirectionTextDirection(Compose)textDirection
줄 바꿈 모드lineBreakModeoverflow(TextStyle)overflow(TextStyle)

모든 속성이 모든 플랫폼에서 동일한 수준으로 제공되는 것은 아닙니다. 예를 들어, 첫 줄 들여쓰기(firstLineHeadIndent)는 iOS에서만 NSMutableParagraphStyle을 통해 완전히 지원됩니다. Android에서는 LeadingMarginSpan을 사용한 SpannableString이 사용되고, Flutter에서는 사용자 지정 TextSpan 및 패딩을 사용한 RichText가 사용됩니다. 크로스 플랫폼 개발(Flutter, React Native)에서는 일부 ParagraphStyle 속성을 컨테이너나 Spacer를 통해 에뮬레이션해야 합니다.

iOS의 ParagraphStyle: NSMutableParagraphStyle

iOS에서 단락 스타일 작업의 주요 도구는 NSMutableParagraphStyle 클래스(NSParagraphStyle의 하위 클래스)입니다. 단락 서식 관리를 위한 완전한 속성 집합을 제공하며 NSAttributedString을 통해 적용됩니다. NSMutableParagraphStyle은 UILabel 및 UITextView뿐만 아니라 CTParagraphStyle을 통한 Core Text에서도 사용됩니다.

swift
// 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+부터 사용 가능)을 사용해야 합니다.

swift
// 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 시스템 및 Compose

Android에서 ParagraphStyle에 대한 접근 방식은 View 시스템과 Jetpack Compose 간에 다릅니다. 기존 View 시스템에서는 단락 매개변수가 TextView의 XML 속성(android:textAlignment, android:lineSpacingExtra) 또는 android.text.style 패키지의 ParagraphStyle 인터페이스 구현을 사용한 SpannableString을 통해 설정됩니다.

kotlin
// 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)를 지원하며, 이는 다국어 텍스트에 특히 유용합니다.

kotlin
// 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: TextHeightBehavior 및 StrutStyle

Flutter에서 ParagraphStyle 패러다임은 전용 클래스로 분리되지 않았습니다 — 대신 TextStyle 매개변수와 추가 클래스의 조합이 사용됩니다. 정렬은 TextAlign을 통해, 줄 간격은 height(단위 없음)를 통해 설정되며, TextHeightBehavior는 첫 번째와 마지막 줄의 표시 들여쓰기를 제어합니다.

dart
// 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 사용을 제공합니다. 이를 통해 통일된 서식 규칙을 유지하면서 단일 단락 내에서 텍스트와 인라인 위젯(아이콘, 이미지)을 결합할 수 있습니다. 그러나 이 접근 방식은 줄 바꿈을 수동으로 제어해야 하며 자동 하이픈 넣기를 지원하지 않습니다.

dart
// 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 및 현지화: LTR/RTL 및 지역별 특징

ParagraphStyle은 각 로케일의 쓰기 방향을 고려해야 합니다. 아랍어, 히브리어 또는 우르두어(오른쪽에서 왼쪽으로 쓰기, RTL)를 지원하는 모바일 앱에서는 들여쓰기와 정렬이 미러링되어야 합니다. iOS는 baseWritingDirection = .natural을 통한 자동 전환을 지원하고, Android는 TextDirection을, Flutter는 textDirection을 지원합니다.

RTL 로케일에 대한 정렬 구성은 특별한 주의가 필요합니다. LTR 모드에서 headIndent가 왼쪽 들여쓰기를 설정하는 경우, RTL에서는 자동으로 오른쪽 들여쓰기가 됩니다. 그러나 정렬이 명시적으로 지정된 경우(NSTextAlignment.natural 대신 NSTextAlignment.left) 모든 구현이 이 전환을 올바르게 처리하는 것은 아닙니다. Google Internationalization Guide(2025)에 따르면, 다국어 앱의 경우 항상 자연 정렬을 사용하고 두 레이아웃 모두에서 들여쓰기를 확인하세요.

kotlin
// 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 작업 시 일반적인 실수

가장 일반적인 실수는 개별 단락의 다른 서식을 고려하지 않고 텍스트 필드의 전역 속성만을 통해 ParagraphStyle을 사용하는 것입니다. 으로 구분된 여러 단락이 있는 UILabel 또는 TextView에서 ParagraphStyle은 각 단락에 대해 다른 스타일의 속성 텍스트를 사용하지 않는 한 전체 텍스트에 균일하게 적용됩니다.

  • paragraphSpacingBefore 무시 — 많은 개발자가 paragraphSpacing을 설정하지만 paragraphSpacingBefore를 잊습니다. 블록의 첫 번째 단락의 경우 paragraphSpacingBefore는 추가 컨테이너를 만들지 않고 위쪽 여백을 설정할 수 있습니다. 이는 제목이 있는 목록에 특히 유용합니다.
  • 자연 정렬 대신 하드코딩된 정렬(left/right) — 앱이 RTL 로케일을 지원하는 경우 natural 대신 NSTextAlignment.left 또는 TextAlign.Start를 사용하면 아랍어 및 히브리어 로케일에서 잘못된 표시가 발생합니다.
  • 줄 바꿈 모드 확인 부족 — 좁은 컨테이너(목록, 사이드바)에서 잘못된 lineBreakMode는 단어 잘림을 초래합니다. byWordWrapping을 사용하고 특정 로케일의 컨텍스트에서 긴 단어를 확인하세요.
  • 다른 ParagraphStyle과 Spannable 혼합 — SPAN_PARAGRAPH로 Spannable을 설정할 때 단락 경계를 올바르게 계산하는 것이 중요합니다. 실제 단락 경계와 시작/끝 위치가 일치하지 않으면 스타일이 무시됩니다.
  • 잊혀진 기준선 정렬 — 고정 lineHeight(minimumLineHeight)로 ParagraphStyle을 사용할 때 기준선 텍스트 정렬이 활성화되어 있는지 확인하세요. iOS에서는 label.baselineAdjustment = .alignBaselines가 사용됩니다.

UX Collective — Common Typography Bugs in Mobile Apps(2025)에 따르면, ParagraphStyle 문제는 모바일 애플리케이션의 모든 타이포그래픽 버그의 18%를 차지합니다. 가장 심각한 경우는 잘못된 paragraphSpacing으로 인해 다른 줄에서 텍스트가 겹치거나 RTL 로케일이 LTR 들여쓰기로 표시되는 경우입니다. 다양한 언어의 테스트 문자열로 각 ParagraphStyle 매개변수에 대한 단위 테스트를 만드는 것이 좋습니다.

자주 묻는 질문

iOS에서 ParagraphStyle과 TextStyle의 차이점은 무엇인가요?

NSMutableParagraphStyle은 단락 서식(정렬, 들여쓰기, 줄 간격)을 관리하고, TextStyle은 문자 속성(글꼴, 색상, 크기)을 관리합니다. 둘 다 NSAttributedString을 통해 적용됩니다. ParagraphStyle은 단락 수준에서, TextStyle은 문자 수준에서 작동합니다. 하나의 단락에 여러 TextStyle 인스턴스가 있을 수 있지만 ParagraphStyle은 단락당 하나만 있습니다.

Jetpack Compose에서 첫 줄 들여쓰기를 설정하는 방법은?

Jetpack Compose에서 첫 줄 들여쓰기는 TextStyle 내의 TextIndent를 통해 설정됩니다: TextStyle(textIndent = TextIndent(firstLine = 16.sp)). 텍스트와 함께 크기가 조정되도록 값은 sp여야 합니다. 여러 줄 텍스트의 경우 들여쓰기는 새 단락( 문자)을 시작하는 각 줄에 적용됩니다. 첫 번째 단락의 경우 들여쓰기가 항상 적용됩니다.

SwiftUI에서 단락 간격을 구성하는 방법은?

SwiftUI에는 paragraphSpacing에 직접 해당하는 것이 없습니다. 단락 간격을 위해서는 NSMutableParagraphStyle과 paragraphSpacing 속성을 사용한 AttributedString(iOS 15+)을 사용하세요. 또는 Text("...\n\n...")를 통해 단락을 구분하고 텍스트 블록 사이에 .padding()을 추가합니다. 복잡한 타이포그래픽 시나리오의 경우 UILabelRepresentable을 통해 NSAttributedString을 사용합니다.

Android TextView에서 paragraphSpacing이 작동하지 않는 이유는?

Android의 TextView에는 paragraphSpacing 속성이 없습니다 — LeadingMarginSpan을 사용한 SpannableString 또는 사용자 지정 LineBackgroundSpan을 통해 설정됩니다. 줄 간격에는 setLineSpacing을, 단락 간격에는 추가 으로 단락을 구분하거나 여러 TextView 인스턴스의 복합 컨테이너를 사용하세요.

ParagraphStyle이 모바일 앱 접근성에 어떤 영향을 미치나요?

적절한 ParagraphStyle은 접근성을 향상시킵니다: 충분한 paragraphSpacing은 인지 장애가 있는 사용자가 단락 경계를 더 잘 구분하는 데 도움이 됩니다. WCAG 2.2는 단락의 시각적 구분(들여쓰기 또는 간격)을 권장합니다. ParagraphSpacing은 1.5 × line-height 이상이어야 합니다. RTL 로케일의 경우 들여쓰기가 올바르게 미러링되는지 확인하세요.

요약

  • ParagraphStyle — 단락 서식 규칙 집합: 정렬, 들여쓰기, 줄 및 단락 간격.
  • iOS — 14개 이상의 매개변수가 있는 NSMutableParagraphStyle, NSAttributedString을 통해 적용; SwiftUI에서는 AttributedString(iOS 15+).
  • Android View — ParagraphStyle 구현(AlignmentSpan, LeadingMarginSpan)을 사용한 SpannableString.
  • Android Compose — TextStyle.textAlign, lineHeight, textIndent 및 줄 바꿈 제어를 위한 LineBreak.
  • Flutter — 줄 높이 고정을 위한 TextStyle.height, TextAlign, TextHeightBehavior 및 StrutStyle의 조합.
  • 현지화 — RTL 로케일 지원을 위해 자연 정렬 사용; 두 레이아웃에서 들여쓰기 확인.
  • 일반적인 실수 — 자연 대신 하드코딩된 정렬, paragraphSpacingBefore 무시, 좁은 컨테이너에 대한 잘못된 lineBreakMode.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기