From 1a60a5427a997db7132811295e69efcfbbfc3605 Mon Sep 17 00:00:00 2001 From: JURI <80569323+juri123123@users.noreply.github.com> Date: Wed, 22 Jul 2026 01:40:17 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20#476=20-=20=EC=8B=9C=EA=B0=84=20?= =?UTF-8?q?=ED=91=9C=EA=B8=B0=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ByeBoo-iOS/ByeBoo-iOS/Data/Model/Util/ServerDateFormatter.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/ByeBoo-iOS/ByeBoo-iOS/Data/Model/Util/ServerDateFormatter.swift b/ByeBoo-iOS/ByeBoo-iOS/Data/Model/Util/ServerDateFormatter.swift index 25f2e112..e7514006 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Data/Model/Util/ServerDateFormatter.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Data/Model/Util/ServerDateFormatter.swift @@ -21,7 +21,6 @@ final class ServerDateFormatter { formatter.do { $0.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" $0.locale = Locale(identifier: "en_US_POSIX") - $0.timeZone = TimeZone(secondsFromGMT: 0) } } From e108934b83b8d7566e36bdbd63a127f665c14316 Mon Sep 17 00:00:00 2001 From: JURI <80569323+juri123123@users.noreply.github.com> Date: Wed, 22 Jul 2026 02:03:40 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[Fix]=20#476=20-=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ByeBoo-iOS.xcodeproj/project.pbxproj | 8 +- .../Presentation/Extension/UITableView+.swift | 3 + .../Cells/CommentTableViewCell.swift | 80 ++++++++++++++----- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/ByeBoo-iOS/ByeBoo-iOS.xcodeproj/project.pbxproj b/ByeBoo-iOS/ByeBoo-iOS.xcodeproj/project.pbxproj index 2967de7b..eacd3cbd 100644 --- a/ByeBoo-iOS/ByeBoo-iOS.xcodeproj/project.pbxproj +++ b/ByeBoo-iOS/ByeBoo-iOS.xcodeproj/project.pbxproj @@ -310,7 +310,7 @@ CODE_SIGN_ENTITLEMENTS = "ByeBoo-iOS/ByeBoo-Dev.entitlements"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 14; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z6682N5G5D; @@ -354,7 +354,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 14; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = Z6682N5G5D; GENERATE_INFOPLIST_FILE = YES; @@ -515,7 +515,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 14; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 18.2; MACOSX_DEPLOYMENT_TARGET = 15.2; @@ -537,7 +537,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 14; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 18.2; MACOSX_DEPLOYMENT_TARGET = 15.2; diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Extension/UITableView+.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Extension/UITableView+.swift index fc2a002b..d611132c 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Extension/UITableView+.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Extension/UITableView+.swift @@ -7,6 +7,9 @@ import UIKit +// intrinsicContentSize가 없어 콘텐츠 크기만큼 스스로 커지지 못한다. +// isScrollEnabled = false로 쓰고 contentSize를 intrinsicContentSize로 노출시켜, +// 바깥 UIScrollView 안에 스크롤 없이 끼워넣어도 콘텐츠 높이에 맞게 자동으로 커지게 한다. final class SelfSizingTableView: UITableView { override var contentSize: CGSize { didSet { diff --git a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/CommonQuest/Cells/CommentTableViewCell.swift b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/CommonQuest/Cells/CommentTableViewCell.swift index 9fa1dafb..362f8639 100644 --- a/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/CommonQuest/Cells/CommentTableViewCell.swift +++ b/ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/CommonQuest/Cells/CommentTableViewCell.swift @@ -41,6 +41,9 @@ final class CommentTableViewCell: UITableViewCell { private var isMyComment: Bool = false + private var showAllText: Bool = false + private var lastTruncationWidth: CGFloat = -1 + override init( style: UITableViewCell.CellStyle, reuseIdentifier: String? @@ -57,6 +60,30 @@ final class CommentTableViewCell: UITableViewCell { fatalError("init(coder:) has not been implemented") } + override func layoutSubviews() { + super.layoutSubviews() + + // bounds.width가 이 기기 폭으로 확정된 뒤에만 계산해야 기기별 오차가 없다. + let width = commentTextView.bounds.width + guard width > 0, width != lastTruncationWidth else { return } + lastTruncationWidth = width + + updateTextTruncation() + } + + // exclusionPaths 변경으로 layoutSubviews가 재호출돼도 width는 안 바뀌므로 위 guard에서 걸러진다. + private func updateTextTruncation() { + commentTextView.textContainer.maximumNumberOfLines = 0 + commentTextView.textContainer.exclusionPaths = [] + + if showAllText { + commentTextView.invalidateIntrinsicContentSize() + moreLabel.isHidden = true + } else { + applyStyleWhenHideText() + } + } + private func setUI() { contentView.addSubviews(profileIcon, nicknameLabel, dateLabel, menuButton, commentTextView, moreLabel) } @@ -229,20 +256,17 @@ extension CommentTableViewCell { self.profileIcon.image = profileIcon dateLabel.text = writtenAt self.content = content + self.showAllText = showAllText commentTextView.applyTextViewStyle(style: .body6R14, text: content, color: .grayscale100) - layoutIfNeeded() - commentTextView.textContainer.maximumNumberOfLines = 0 commentTextView.textContainer.exclusionPaths = [] - - if showAllText { - commentTextView.invalidateIntrinsicContentSize() - moreLabel.isHidden = true - } else { - let numberOfLines = commentTextView.numberOfLine() - applyStyleWhenHideText(numberOfLines) - } + + // setNeedsLayout만으로는 부족하다: commentListView가 스크롤 없는 self-sizing 테이블이라 + // 일반 테이블처럼 셀이 화면에 나타날 때 자연스럽게 layoutSubviews가 재호출되지 않는다. + // layoutIfNeeded로 직접 트리거해야 truncation 계산(layoutSubviews)이 그 자리에서 실행된다. + lastTruncationWidth = -1 + layoutIfNeeded() } func updateReplyCount(replyCount: Int) { @@ -252,16 +276,37 @@ extension CommentTableViewCell { } extension CommentTableViewCell { - private func applyStyleWhenHideText(_ numberOfLines: Int) { - moreLabel.isHidden = numberOfLines > 5 ? false : true - commentTextView.textContainer.maximumNumberOfLines = 5 - + private func applyStyleWhenHideText() { + let textContainer = commentTextView.textContainer + let layoutManager = commentTextView.layoutManager + + // textContainer.size는 UITextView가 자기 layoutSubviews에서 뒤늦게 동기화하므로 직접 맞춰준다. + textContainer.size = CGSize(width: commentTextView.bounds.width, height: .greatestFiniteMagnitude) + textContainer.maximumNumberOfLines = 5 + + // glyphRange(for:)는 잘려도 전체 glyph 수를 그대로 반환해 truncation 판단에 못 쓴다. + // 마지막 줄이 실제로 잘렸는지는 truncatedGlyphRange(inLineFragmentForGlyphAt:)로 확인한다. + layoutManager.ensureLayout(for: textContainer) + let glyphRange = layoutManager.glyphRange(for: textContainer) + var isTruncated = false + if glyphRange.length > 0 { + let lastGlyphIndex = NSMaxRange(glyphRange) - 1 + let truncatedRange = layoutManager.truncatedGlyphRange(inLineFragmentForGlyphAt: lastGlyphIndex) + isTruncated = truncatedRange.location != NSNotFound + } + + moreLabel.isHidden = !isTruncated + + guard isTruncated else { + commentTextView.textContainer.exclusionPaths = [] + return + } + let moreLabelWidth: CGFloat = moreLabel.intrinsicContentSize.width let contentHeight = commentTextView.sizeThatFits( CGSize(width: commentTextView.bounds.width, height: .infinity) ).height - - + let lineHeight: CGFloat if let paragraphStyle = commentTextView.attributedText?.attribute(.paragraphStyle, at: 0, effectiveRange: nil) as? NSParagraphStyle, @@ -270,14 +315,13 @@ extension CommentTableViewCell { } else { lineHeight = commentTextView.font?.lineHeight ?? 0 } - + let exclusionRect = CGRect( x: commentTextView.bounds.width - moreLabelWidth - 10, y: contentHeight - lineHeight, width: moreLabelWidth, height: lineHeight ) - ByeBooLogger.debug("가로 : \(exclusionRect.width), 세로: \(exclusionRect.height)" ) commentTextView.textContainer.exclusionPaths = [UIBezierPath(rect: exclusionRect)] }