Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- task cancel
- custombottomsheet
- RxSwift
- reactorkit
- claen architecture
- task cancellation
- button configuration
- Tuist
- 타임라인 포맷팅
- uikit toast
- domain data
- rxdatasources
- swift dashed line
- swift concurrency
- swift 백준
- custom navigation bar
- swift 점선
- paragraph style
- identifiable
- swift navigationcontroller
- swift custom ui
- SWIFT
- custom ui
- traits
- DP
- tusit font 추가 방법
- coordinator
- swift bottomsheet
- UIKit
- BFS
Archives
- Today
- Total
김경록의 앱 개발 여정
[Swift] 행간, 첫 줄 들여쓰기 등 적용하기 Paragraph Style 본문
이전 작성한 포스팅 공백이 포함된 커스텀 뷰 구현기 를 작성 후 아쉬움이 남아 더 나아 보이는 좋은 방법을 찾았고 이를 기록하고자 합니다.
Paragraph Style이란?
NSParagraphStyle과 NSMutableParagraphStyle은 iOS에서 텍스트의 문단 스타일을 제어하는 데 사용되는 클래스입니다.
이를 통해 텍스트의 줄 간격, 들여쓰기, 정렬, 줄 바꿈 모드 등 다양한 문단 관련 속성을 설정할 수 있습니다.
주로 NSAttributedString과 함께 사용되며, 텍스트에 대한 세부적인 스타일링을 가능하게 합니다.
주요 속성들
- lineSpacing
- 문단 내 줄 간격을 설정합니다.
- 기본값은 0이고, 양수 값으로 설정하면 줄 간 간격이 늘어납니다.
- paragraphSpacing
- 문단 간 간격을 설정합니다.
- 문단의 마지막 줄과 다음 문단의 첫 줄 사이의 간격을 조정합니다.
- alignment
- 텍스트 정렬 방식을 설정합니다.
- 예: .left, .center, .right, .justified
- firstLineHeadIndent
- 문단의 첫 줄 들여 쓰기 간격을 설정합니다.
- 예: 목록이나 강조 문단 작성 시 사용.
- headIndent
- 문단의 모든 줄(첫 줄 제외)의 들여쓰기 간격을 설정합니다.
- tailIndent
- 텍스트의 오른쪽 경계(끝점)를 설정합니다.
- lineBreakMode
- 텍스트 줄 바꿈 방식을 설정합니다.
- 예:. byTruncatingTail,. byWordWrapping
- minimumLineHeight / maximumLineHeight
- 줄 높이의 최소 및 최댓값을 설정합니다.
- baseWritingDirection
- 텍스트의 쓰기 방향을 설정합니다.
- 예:. natural,. leftToRight,. rightToLeft
사용 예시
지난번과 비슷하지만 간소화된 ui를 작성해 보았습니다.
분홍색으로 칠해진 '스포츠' 부분을 카테고리, 나머지 제목 부분을 타이틀이라 칭하겠습니다.
해당 ui에서 의도된 부분은 다음과 같습니다.
- 카테고리는 배경색을 가지며, CornerRadius 값을 가집니다.
- 타이틀 부분은 카테고리와 이어지듯 보이며 최대 두줄로 표현됩니다. 단, 줄 바꿈 시 카테고리 바로 아래쪽으로 이어나갑니다.
- 카테고리와 타이틀은 폰트가 서로 다릅니다.
이전에 어떻게 구현했었는지는 따로 다루지 않겠습니다.
타이틀에 firstLineHeadIndent 속성을 사용하여 문단 첫 시작에 공백을 포함시킬 수 있었습니다.
단, 해당 넓이는 동적으로 계산되어야 하므로 카테고리의 넓이가 완전히 정해진 후 계산되어야 합니다.
전체 코드는 아래와 같습니다. 주석이 쓰인 부분만 보셔도 무방합니다.
더보기
import UIKit
import SnapKit
class ViewController: UIViewController {
let categoryView: UIView = {
let view = UIView()
view.backgroundColor = .magenta
view.layer.cornerRadius = 4
view.layer.masksToBounds = true
return view
}()
let categoryLabel: UILabel = {
let label = UILabel()
label.textColor = .white
label.font = .boldSystemFont(
ofSize: 12
)
label.textAlignment = .center
label.text = "스포츠"
return label
}()
let titleView: UIView = {
let view = UIView()
return view
}()
let titleLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.font = .boldSystemFont(ofSize: 16)
label.numberOfLines = 2
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setlayout()
setConstraints()
}
// category의 넓이가 구해지고 사용되어야하므로
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
configureHeadInset()
}
// 주요 사용 예시
func configureHeadInset() {
// categoryView의 넓이를 기반으로 firstLineHeadIndent 설정
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.firstLineHeadIndent = categoryView.frame.width + 8 // 여백 추가 (옵션)
let attributedText = NSMutableAttributedString(string: "요키치 - 웨스트브룩 NBA 역사상 최초의 동반 트리플 더블 2회 달성")
attributedText.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedText.length))
titleLabel.attributedText = attributedText
}
func setlayout() {
view.addSubview(categoryView)
categoryView.addSubview(categoryLabel)
view.addSubview(titleView)
titleView.addSubview(titleLabel)
}
func setConstraints() {
categoryView.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide).offset(100)
$0.leading.equalTo(view.safeAreaLayoutGuide).offset(20)
$0.width.equalTo(41)
$0.height.equalTo(18)
}
categoryLabel.snp.makeConstraints {
$0.top.bottom.trailing.leading.equalTo(categoryView)
}
titleView.snp.makeConstraints {
$0.top.equalTo(view.safeAreaLayoutGuide).offset(100)
$0.leading.equalTo(view.safeAreaLayoutGuide).offset(20)
$0.trailing.equalTo(view.safeAreaLayoutGuide).offset(-20)
}
titleLabel.snp.makeConstraints {
$0.top.bottom.trailing.leading.equalTo(titleView)
}
}
}
또한 해당 방식을 사용하면 이전에 미처 신경 쓰지 못한 부분까지 구현할 수 있었습니다.
LineSpace 속성을 추가해 보겠습니다.
configureHeadInset() 내에서 paragraphStyle.lineSpacing = 5로 값을 지정해줌
더욱 자연스러운 문단 내 줄 간격을 적용할 수 있었습니다.
사용법도 간단하고 강력한 기능을 제공해 주어서 앞으로도 애용하게 될 것 같습니다.
'TIL' 카테고리의 다른 글
[Swift] 유튜브처럼 타임라인 포맷팅하기 (0) | 2025.03.10 |
---|---|
[Swift UIKit] Button Configuration 사용 시 의도치않은 inset 줄이기 (0) | 2025.02.07 |
[Tuist] Tuist 를 통한 커스텀 폰트 추가 방법 (0) | 2025.01.13 |
[Swift]ReactorKit, Coordinator 그리고 화면 이동과 데이터 전달 (0) | 2025.01.09 |
[ReactorKit] 기본 예제 분석하고 내 프로젝트에 적용하기 (0) | 2025.01.09 |