fix(community): 커뮤니티 전체 아이템 말줄임과 폰트를 정렬, 텍스트 확장 동작을 개선한다
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
// Created by klaus on 2023/12/15.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Kingfisher
|
||||
import SDWebImageSwiftUI
|
||||
@@ -20,7 +21,9 @@ struct CreatorCommunityAllItemView: View {
|
||||
|
||||
@State var isLike = false
|
||||
@State var likeCount = 0
|
||||
@State private var textHeight: CGFloat = .zero
|
||||
@State private var isContentExpanded = false
|
||||
@State private var isContentTruncated = false
|
||||
@State private var contentTextWidth: CGFloat = 0
|
||||
|
||||
@StateObject var playManager = CreatorCommunityMediaPlayerManager.shared
|
||||
@StateObject var contentPlayManager = ContentPlayManager.shared
|
||||
@@ -55,11 +58,11 @@ struct CreatorCommunityAllItemView: View {
|
||||
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
Text(item.creatorNickname)
|
||||
.appFont(size: 13.3, weight: .medium)
|
||||
.appFont(size: 18, weight: .bold)
|
||||
.foregroundColor(Color.grayee)
|
||||
|
||||
Text(item.relativeTimeText())
|
||||
.appFont(size: 13.3, weight: .light)
|
||||
.appFont(size: 14, weight: .regular)
|
||||
.foregroundColor(Color.gray77)
|
||||
}
|
||||
.padding(.leading, 11)
|
||||
@@ -73,22 +76,43 @@ struct CreatorCommunityAllItemView: View {
|
||||
}
|
||||
}
|
||||
|
||||
DetectableTextView(text: item.content, textSize: 13.3, font: Font.preMedium.rawValue)
|
||||
.frame(
|
||||
width: screenSize().width - 42,
|
||||
height: textHeight
|
||||
Group {
|
||||
if isContentExpanded {
|
||||
Text(linkedAttributedContent(from: item.content))
|
||||
} else {
|
||||
Text(item.content)
|
||||
.lineLimit(3)
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
}
|
||||
.appFont(size: 18, weight: .regular)
|
||||
.foregroundColor(Color(hex: "B0BEC5"))
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.contentShape(Rectangle())
|
||||
.background(
|
||||
GeometryReader { proxy in
|
||||
Color.clear
|
||||
.onAppear {
|
||||
updateContentWidth(proxy.size.width)
|
||||
}
|
||||
.onChange(of: proxy.size.width) { newWidth in
|
||||
updateContentWidth(newWidth)
|
||||
}
|
||||
}
|
||||
)
|
||||
.onTapGesture {
|
||||
guard isContentTruncated || isContentExpanded else { return }
|
||||
isContentExpanded.toggle()
|
||||
}
|
||||
.onAppear {
|
||||
self.textHeight = self.estimatedHeight(
|
||||
for: item.content,
|
||||
width: screenSize().width - 42
|
||||
)
|
||||
let width = contentTextWidth > 0 ? contentTextWidth : (screenSize().width - 42)
|
||||
updateContentTruncationState(for: item.content, width: width)
|
||||
}
|
||||
.onChange(of: item.content) { newText in
|
||||
self.textHeight = self.estimatedHeight(
|
||||
for: newText,
|
||||
width: screenSize().width - 42
|
||||
)
|
||||
isContentExpanded = false
|
||||
let width = contentTextWidth > 0 ? contentTextWidth : (screenSize().width - 42)
|
||||
updateContentTruncationState(for: newText, width: width)
|
||||
}
|
||||
|
||||
if item.price <= 0 || item.existOrdered {
|
||||
@@ -97,6 +121,7 @@ struct CreatorCommunityAllItemView: View {
|
||||
WebImage(url: URL(string: imageUrl))
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
|
||||
.clipped()
|
||||
|
||||
if let audioUrl = item.audioUrl {
|
||||
@@ -149,16 +174,69 @@ struct CreatorCommunityAllItemView: View {
|
||||
}
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.vertical, 11)
|
||||
.background(Color.gray22)
|
||||
.cornerRadius(5.3)
|
||||
.frame(maxWidth: .infinity)
|
||||
.background(Color(hex: "263238"))
|
||||
.cornerRadius(16)
|
||||
.padding(.horizontal, 13.3)
|
||||
}
|
||||
|
||||
private func updateContentWidth(_ width: CGFloat) {
|
||||
guard width > 0 else { return }
|
||||
contentTextWidth = width
|
||||
updateContentTruncationState(for: item.content, width: width)
|
||||
}
|
||||
|
||||
private func updateContentTruncationState(for text: String, width: CGFloat) {
|
||||
let fullHeight = estimatedHeight(for: text, width: width)
|
||||
let collapsedHeight = estimatedCollapsedHeight(lineLimit: 3)
|
||||
isContentTruncated = fullHeight > (collapsedHeight + 0.5)
|
||||
}
|
||||
|
||||
private func estimatedCollapsedHeight(lineLimit: Int) -> CGFloat {
|
||||
let font = UIFont(name: Font.preRegular.rawValue, size: 18) ?? UIFont.systemFont(ofSize: 18, weight: .regular)
|
||||
let lineCount = CGFloat(lineLimit)
|
||||
return font.lineHeight * lineCount
|
||||
}
|
||||
|
||||
private func estimatedHeight(for text: String, width: CGFloat) -> CGFloat {
|
||||
let textView = UITextView(frame: CGRect(x: 0, y: 0, width: width, height: .greatestFiniteMagnitude))
|
||||
textView.font = UIFont.systemFont(ofSize: 13.3)
|
||||
textView.text = text
|
||||
return textView.sizeThatFits(CGSize(width: width, height: .greatestFiniteMagnitude)).height
|
||||
let attributes: [NSAttributedString.Key: Any] = [
|
||||
.font: UIFont(name: Font.preRegular.rawValue, size: 18) ?? UIFont.systemFont(ofSize: 18, weight: .regular)
|
||||
]
|
||||
|
||||
let rect = NSAttributedString(string: text, attributes: attributes)
|
||||
.boundingRect(
|
||||
with: CGSize(width: width, height: .greatestFiniteMagnitude),
|
||||
options: [.usesLineFragmentOrigin, .usesFontLeading],
|
||||
context: nil
|
||||
)
|
||||
|
||||
return ceil(rect.height)
|
||||
}
|
||||
|
||||
private func linkedAttributedContent(from text: String) -> AttributedString {
|
||||
var attributedText = AttributedString(text)
|
||||
|
||||
guard
|
||||
let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
|
||||
else {
|
||||
return attributedText
|
||||
}
|
||||
|
||||
let nsText = text as NSString
|
||||
let matches = detector.matches(in: text, options: [], range: NSRange(location: 0, length: nsText.length))
|
||||
|
||||
for match in matches {
|
||||
guard
|
||||
let url = match.url,
|
||||
let range = Range(match.range, in: attributedText)
|
||||
else {
|
||||
continue
|
||||
}
|
||||
|
||||
attributedText[range].link = url
|
||||
}
|
||||
|
||||
return attributedText
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user