Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions ByeBoo-iOS/ByeBoo-iOS.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분 제거해주신 거군요! 감사합니다

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

import UIKit

// intrinsicContentSize가 없어 콘텐츠 크기만큼 스스로 커지지 못한다.
// isScrollEnabled = false로 쓰고 contentSize를 intrinsicContentSize로 노출시켜,
// 바깥 UIScrollView 안에 스크롤 없이 끼워넣어도 콘텐츠 높이에 맞게 자동으로 커지게 한다.
final class SelfSizingTableView: UITableView {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼 콘텐츠 크기에 동적으로 반응해야 하는 테이블 뷰는 모두 UITableView가 아닌 SelfSizingTableView를 상속해야 하는 걸까요?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SelfSizingTableView는 스크롤 없이 상위 스크롤뷰에 끼워 넣는 테이블뷰에 필요하다고 이해했습니다. . .
CommonQuestReplyView처럼 리스트가 화면의 유일한 스크롤 영역이면 평범한 UITableView로 충분하고, CommonQuestHistoryView처럼 질문/답변과 함께 하나의 스크롤 안에 얹혀야 할 때만 SelfSizingTableView를 사용해주면 될 것 같아요 !

혹시 아니라면 꼬옥 알려주길 바랍니다 . . .
@y-eonee @dev-domo

override var contentSize: CGSize {
didSet {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand All @@ -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)
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Comment on lines 306 to 308

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

CGFloat.infinity 대신 CGFloat.greatestFiniteMagnitude 사용을 권장합니다.

sizeThatFits.infinity를 전달하면 내부적으로 CoreGraphics 연산 시 의도치 않은 동작이나 충돌이 발생할 위험이 있습니다. 안전하게 최대 크기를 지정하려면 284번째 줄에서 사용하신 것처럼 .greatestFiniteMagnitude를 사용하는 것이 좋습니다.

💻 수정 제안
         let contentHeight = commentTextView.sizeThatFits(
-            CGSize(width: commentTextView.bounds.width, height: .infinity)
+            CGSize(width: commentTextView.bounds.width, height: .greatestFiniteMagnitude)
         ).height
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let contentHeight = commentTextView.sizeThatFits(
CGSize(width: commentTextView.bounds.width, height: .infinity)
).height
let contentHeight = commentTextView.sizeThatFits(
CGSize(width: commentTextView.bounds.width, height: .greatestFiniteMagnitude)
).height
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@ByeBoo-iOS/ByeBoo-iOS/Presentation/Feature/Quest/View/CommonQuest/Cells/CommentTableViewCell.swift`
around lines 306 - 308, Update the sizeThatFits call calculating contentHeight
in CommentTableViewCell to use CGFloat.greatestFiniteMagnitude for the CGSize
height instead of .infinity, matching the existing safe sizing approach
elsewhere in the cell.




let lineHeight: CGFloat
if let paragraphStyle = commentTextView.attributedText?.attribute(.paragraphStyle, at: 0, effectiveRange: nil)
as? NSParagraphStyle,
Expand All @@ -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)]
}

Expand Down
Loading