Swift UILabel 텍스트 부분 색상/폰트/볼드/밑줄 적용하기
개발하다 보면 특정 부분에 볼드되거나 색상 변경, 밑줄이 들어가는 경우가 종종 있습니다.
공통적으로 사용할 수 있기 때문에 UILabel을 extension하여 구현해 두면 요긴하게 쓸 수 있죠!
위 예시를 보면 "지날 달 보러가기" 는 밑줄을,
"감정 카드 저장을 원하시면 설정에서 사진 접근을 허용하세요." 는 부분 볼드 처리를 해야합니다.
각 함수를 구현하기 전 개념을 짚고 넘어가 봅시다~
개념 이해하기
부분 적용을 위해서는 UILabel의 attributedText를 설정해야합니다.
아래 코드는 UIKit.UILabel을 발췌했습니다.
attributedText의 주석을 보시면 'attributedText 지정 시 text, font, textColor 등 모든 속성이 무시된다' 고 하네요.
import Foundation
//
// UILabel.h
// UIKit
//
// Copyright (c) 2006-2018 Apple Inc. All rights reserved.
//
@available(iOS 2.0, *)
@MainActor open class UILabel : UIView, NSCoding, UIContentSizeCategoryAdjusting {
open var text: String? // default is nil
open var font: UIFont! // default is nil (system font 17 plain)
open var textColor: UIColor! // default is labelColor
open var shadowColor: UIColor? // default is nil (no shadow)
open var shadowOffset: CGSize // default is CGSizeMake(0, -1) -- a top shadow
open var textAlignment: NSTextAlignment // default is NSTextAlignmentNatural (before iOS 9, the default was NSTextAlignmentLeft)
open var lineBreakMode: NSLineBreakMode // default is NSLineBreakByTruncatingTail. used for single and multiple lines of text
// the underlying attributed string drawn by the label, if set, the label ignores the properties above.
@available(iOS 6.0, *)
@NSCopying open var attributedText: NSAttributedString? // default is nil
UILabel text를 AttributedString으로 변환하기
그렇다면 attributedText를 지정하면 그 전에 내가 설정한 모든 속성 값이 초기화 된다는 말인데...
초기화 되는 문제를 미연에 방지하기 위해
내가 설정한 text와 font를 attributedString으로 바꾸어 주는 함수를 추가했습니다.
import UIKit
extension UILabel {
/* AttributedString이 설정되어있지 않으면 생성하여 반환한다. */
private func mutableAttributedString() -> NSMutableAttributedString? {
guard let labelText = self.text, let labelFont = self.font else { return nil }
var attributedString: NSMutableAttributedString?
if let attributedText = self.attributedText {
attributedString = attributedText.mutableCopy() as? NSMutableAttributedString
} else {
attributedString = NSMutableAttributedString(string: labelText,
attributes: [NSAttributedString.Key.font :labelFont])
}
return attributedString
}
}
더 많은 NSAttributedString.key를 보고 싶다면 공식 문서를 참고해주세요.
UILabel 특정 부분 Color 지정하기
color 지정은 UILabel.textColor로 지정할 수 있지만 부분 컬러를 지정하기 위해 NSRange 타입을 parameter로 받았습니다.
먼저 attributedString으로 변환한 뒤 NSAttributedString.key.foregroundColor를 해당 범위만큼만 다른 색상으로 대체합니다.
extension UILabel {
/* 텍스트 구간 색상 변경 */
func setTextColor(_ color: UIColor, range: NSRange) {
guard let attributedString = self.mutableAttributedString() else { return }
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
self.attributedText = attributedString
}
/* AttributedString이 설정되어있지 않으면 생성하여 반환한다. */
private func mutableAttributedString() -> NSMutableAttributedString? {
guard let labelText = self.text, let labelFont = self.font else { return nil }
var attributedString: NSMutableAttributedString?
if let attributedText = self.attributedText {
attributedString = attributedText.mutableCopy() as? NSMutableAttributedString
} else {
attributedString = NSMutableAttributedString(string: labelText,
attributes: [NSAttributedString.Key.font :labelFont])
}
return attributedString
}
}
UILabel 특정 부분 Font 지정하기
Color 지정과 유사하게, NSAttributedString.key.font를 적용합니다.
extension UILabel {
/* 텍스트 구간 폰트 변경 */
func setFont(_ font: UIFont, range: NSRange) {
guard let attributedString = self.mutableAttributedString() else { return }
attributedString.addAttribute(NSAttributedString.Key.font, value: font, range: range)
self.attributedText = attributedString
}
/* 텍스트 구간 볼드 폰트 변경 */
func setBoldFont(_ boldFontName: String, range: NSRange) {
guard let font = self.font,
let boldFont = UIFont(name: boldFontName, size: font.pointSize) else {
return
}
return setFont(boldFont, range: range)
}
/* AttributedString이 설정되어있지 않으면 생성하여 반환한다. */
private func mutableAttributedString() -> NSMutableAttributedString? {
guard let labelText = self.text, let labelFont = self.font else { return nil }
var attributedString: NSMutableAttributedString?
if let attributedText = self.attributedText {
attributedString = attributedText.mutableCopy() as? NSMutableAttributedString
} else {
attributedString = NSMutableAttributedString(string: labelText,
attributes: [NSAttributedString.Key.font :labelFont])
}
return attributedString
}
}
UILabel 특정 부분 밑줄(Underline) 지정하기
NSAttributedString.key.underlineStyle로 밑줄을 적용합니다.
NSUnderlineStyle의 rawValue (int)를 넣어주면 됩니다.
extension UILabel {
/* 밑줄 추가 */
func setUnderline(range: NSRange) {
guard let attributedString = self.mutableAttributedString() else { return }
attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
self.attributedText = attributedString
}
/* AttributedString이 설정되어있지 않으면 생성하여 반환한다. */
private func mutableAttributedString() -> NSMutableAttributedString? {
guard let labelText = self.text, let labelFont = self.font else { return nil }
var attributedString: NSMutableAttributedString?
if let attributedText = self.attributedText {
attributedString = attributedText.mutableCopy() as? NSMutableAttributedString
} else {
attributedString = NSMutableAttributedString(string: labelText,
attributes: [NSAttributedString.Key.font :labelFont])
}
return attributedString
}
}
사용할 때는 UIButton의 titleLabel인 경우 아래와 같이 전체 밑줄을 줄 수 있습니다.
btnLastMonth.titleLabel?.setUnderline(range: NSRange(location: 0, length: btnLastMonth.currentTitle?.count ?? 0))
전체 코드
import UIKit
extension UILabel {
/* 텍스트 구간 색상 변경 */
func setTextColor(_ color: UIColor, range: NSRange) {
guard let attributedString = self.mutableAttributedString() else { return }
attributedString.addAttribute(NSAttributedString.Key.foregroundColor, value: color, range: range)
self.attributedText = attributedString
}
/* 텍스트 구간 볼드 폰트 변경 */
func setBoldFont(_ boldFontName: String, range: NSRange) {
guard let font = self.font,
let boldFont = UIFont(name: boldFontName, size: font.pointSize) else {
return
}
return setFont(boldFont, range: range)
}
/* 텍스트 구간 폰트 변경 */
func setFont(_ font: UIFont, range: NSRange) {
guard let attributedString = self.mutableAttributedString() else { return }
attributedString.addAttribute(NSAttributedString.Key.font, value: font, range: range)
self.attributedText = attributedString
}
/* 밑줄 추가 */
func setUnderline(range: NSRange) {
guard let attributedString = self.mutableAttributedString() else { return }
attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
self.attributedText = attributedString
}
/* AttributedString이 설정되어있지 않으면 생성하여 반환한다. */
private func mutableAttributedString() -> NSMutableAttributedString? {
guard let labelText = self.text, let labelFont = self.font else { return nil }
var attributedString: NSMutableAttributedString?
if let attributedText = self.attributedText {
attributedString = attributedText.mutableCopy() as? NSMutableAttributedString
} else {
attributedString = NSMutableAttributedString(string: labelText,
attributes: [NSAttributedString.Key.font :labelFont])
}
return attributedString
}
}