긴 글의 내용이 일정한 길이로 축약되어 나타나는 label 만들기
- 원하는 모양
- 최대 두 줄까지 내용이 보이고 그 뒤에 “… 더보기”가 붙는 형태
//
// UILabel+Ext.swift
import UIKit
extension UILabel {
// label의 폰트, 사이즈를 계산해서 최종적으로 화면에 보여질 글자의 길이
var visibleTextLength: Int {
let font: UIFont = self.font
let mode: NSLineBreakMode = self.lineBreakMode
let labelWidth: CGFloat = self.frame.size.width
let labelHeight: CGFloat = self.frame.size.height
let sizeConstraint = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude) // Label의 크기
if let myText = self.text {
let attributes: [AnyHashable: Any] = [NSAttributedString.Key.font: font]
let attributedText = NSAttributedString(
string: myText,
attributes: attributes as? [NSAttributedString.Key: Any])
let boundingRect: CGRect = attributedText.boundingRect(
with: sizeConstraint,
options: .usesLineFragmentOrigin,
context: nil)
if boundingRect.size.height > labelHeight {
var index: Int = 0
var prev: Int = 0
let characterSet = CharacterSet.whitespacesAndNewlines
repeat {
prev = index
if mode == NSLineBreakMode.byCharWrapping {
index += 1
} else {
index = (myText as NSString).rangeOfCharacter(
from: characterSet,
options: [],
range: NSRange(
location: index + 1,
length: myText.count - index - 1)).location
}
} while index != NSNotFound && index < myText.count && (myText as NSString)
.substring(to: index)
.boundingRect(
with: sizeConstraint,
options: .usesLineFragmentOrigin,
attributes: attributes as? [NSAttributedString.Key: Any], context: nil)
.size
.height <= labelHeight
return prev
}
}
if self.text == nil {
return 0
} else {
return self.text!.count
}
}
// Label에 "... 더보기"와 같은 텍스트를 추가하기 위한 함수
func addTrailing(
with trailingText: String,
moreText: String,
moreTextFont: UIFont,
moreTextColor: UIColor
) {
let readMoreText: String = trailingText + moreText
if self.visibleTextLength == 0 { return }
let lengthForVisibleString: Int = self.visibleTextLength
if let myText = self.text {
let mutableString: String = myText
let trimmedString: String? = (mutableString as NSString).replacingCharacters(
in: NSRange(
location: lengthForVisibleString,
length: myText.count - lengthForVisibleString
), with: "")
let readMoreLength: Int = (readMoreText.count)
guard let safeTrimmedString = trimmedString else { return }
if safeTrimmedString.count <= readMoreLength { return }
let trimmedForReadMore: String = (safeTrimmedString as NSString)
.replacingCharacters(
in: NSRange(
location: safeTrimmedString.count - readMoreLength,
length: readMoreLength)
,with: ""
) + trailingText
let answerAttributed = NSMutableAttributedString(
string: trimmedForReadMore,
attributes: [NSAttributedString.Key.font: self.font as Any]
)
let readMoreAttributed = NSMutableAttributedString(
string: moreText,
attributes: [NSAttributedString.Key.font: moreTextFont,
NSAttributedString.Key.foregroundColor: moreTextColor]
)
answerAttributed.append(readMoreAttributed)
self.attributedText = answerAttributed
}
}
}
- 사용방법
- 이 때 Label의 라인 수는 0으로 설정해두고, 실제로 나타날 라인 수는 Label의 높이로 맞추면 된다.
- font와 line height을 계산해서 자동으로 설정하면 좋겠지만, 일단 50으로 고정하여 사용했더니 2줄이 나타남!
let contentLabel = UILabel().then {
let contentLabel = UILabel().then {
$0.translatesAutoresizingMaskIntoConstraints = false
$0.numberOfLines = 0
$0.font = UIFont(name: "Apple SD Gothic Neo", size: 13)
}
guard let contentTextLength = self.contentLabel.text?.count else { return }
if contentTextLength > 1 {
DispatchQueue.main.async {
self.contentLabel.addTrailing(with: "... ", moreText: "더보기", moreTextFont: .systemFont(ofSize: 13), moreTextColor: UIColor.gray)
}
}
- 참고한 글