Skip to content

Style/#428 댓글, 답글 UI 구현#440

Merged
y-eonee merged 31 commits into
developfrom
style/#428-댓글-ui
May 19, 2026

Hidden character warning

The head ref may contain hidden characters: "style/#428-\ub313\uae00-ui"
Merged

Style/#428 댓글, 답글 UI 구현#440
y-eonee merged 31 commits into
developfrom
style/#428-댓글-ui

Conversation

@y-eonee
Copy link
Copy Markdown
Member

@y-eonee y-eonee commented May 10, 2026

🔗 연결된 이슈

📄 작업 내용

  • 댓글, 답글 뷰의 전반적인 UI 작업을 진행했습니다.
  • 댓글, 답글이 추가됨에 따라 entity가 수정된 부분이 있습니다. dto 부분에 주석처리 된 부분들은 서버 연결하면서 해제할 예정입니다!
  • 키보드 관련 로직을 따로 protocol + extension으로 분리하였습니다.
구현 내용 좋아요 누르기 댓글 리스트
GIF
구현 내용 답글 바텀시트 키보드
GIF

💻 주요 코드 설명

댓글 입력 컴포넌트

CommentTextFieldView

textView.do {
            let offset = (FontManager.body6R14.lineHeight - FontManager.body6R14.font.lineHeight) / 2
            $0.textContainerInset = .init(
                top: offset,
                left: 0,
                bottom: offset,
                right: 0
            )        
            // 그외... 
        }

UITextView 내의 TextContainer에 존재하는 기본 패딩값을 조정하기 위해 offset을 계산하여 넣어주었습니다.
텍스트뷰가 입력 중일 때, 레이아웃이 바뀌는 것들은 모두 UITextViewDelegate 내부에서 분기처리를 해주었습니다.

func textViewDidChange(_ textView: UITextView) {
        let maxHeight = 105.adjustedH
        let fittingHeight = textView.sizeThatFits(CGSize(width: textView.bounds.width, height: .infinity)).height
        
        let shouldScroll = fittingHeight > maxHeight
        textView.isScrollEnabled = shouldScroll
        if !shouldScroll { textView.contentOffset = .zero }

최대 1~5줄까지만 보이고, 6줄부터는 스크롤이 가능하게 하기 위해서 최대 높이를 지정하여 분기처리를 해주었습니다.

더보기 라벨

하 정말 힘들었습니다 어떻게 해결했는지 적어볼게요 ..

  1. TextView의 전체 line 수를 구한다
    UITextView에 텍스트 라인수를 구하는 함수를 하나 만들어서, cell을 configure해줄 때 계산합니다
  2. 라인수에 따라 더보기 라벨이 필요한 경우를 분기처리해줍니다.
  3. exclusivePaths를 사용하여 텍스트의 마지막줄과 더보기라벨의 leading이 붙도록합니다.
    exclusive path는 text container 안에서 텍스트가 렌더링되지 않는 부분을 정할 수 있는 것이라고 합니당
    베지어 패스타입으로 받더라구요 애니메에서보던건데여기서보니까신기햇슴
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)]

Diffable Datasource를 이용한 댓글 테이블뷰 구현

더보기 라벨을 구현하면서, 변경된 UI만 반영할 수 있는 디파블 데이터 소스를 써보고 싶어서 클로드랑 같이.. 도전해보았습니다..

enum CommentSection: Hashable {
    case main
}

enum ReplySection: Hashable {
    case comment
    case replies
}

struct CommentItem: Hashable {
    let entity: CommonQuestCommentEntity
    var showAllText: Bool
}

댓글, 답글은 같은 entity를 사용해서 하나의 item으로 같이 사용합니다

historyVC

 func moreLabelDidTap(commentID: Int) {
        let updatedItems = dataSource.snapshot().itemIdentifiers.map { item -> CommentItem in
            guard item.entity.commentID == commentID else { return item }
            return CommentItem(entity: item.entity, showAllText: true)
        } // comment ID로 구분합니다 

        var snapshot = NSDiffableDataSourceSnapshot<CommentSection, CommentItem>()
        snapshot.appendSections([.main])
        snapshot.appendItems(updatedItems, toSection: .main)
        dataSource.apply(snapshot, animatingDifferences: false) { [weak self] in
            self?.rootView.commentListView.performBatchUpdates(nil)
        }
    }

근데 이렇게 사용하는게 맞는진 잘 모르겠어요 ..
댓글+답글 수정,삭제,신고,차단은 이슈 따로 파서 구현하겠습니다!

y-eonee added 30 commits April 29, 2026 18:45
추후 서버 연결시 주석해제
@y-eonee y-eonee requested review from dev-domo and juri123123 May 10, 2026 14:44
@y-eonee y-eonee self-assigned this May 10, 2026
@y-eonee y-eonee linked an issue May 10, 2026 that may be closed by this pull request
1 task
Copy link
Copy Markdown
Collaborator

@juri123123 juri123123 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다 !


import UIKit

protocol KeyboardHandleProtocol: UIViewController {
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.

우와 protocol이 UIViewController를 상속받은 건가요 .......?????? 컴파일 에러가 발생하지 않았나요 . . . ? 신기하네요 ...

프로토콜에서 채택 타입에 따른 제약은 저는 보통

extension KeyboardHandleProtocol where Self: UIViewController { ~

이런식으로 사용했던 것 같은데 ...!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

생각해보니 안나더라고요.... 왜지.. where로 수정하겠습니다!!

let writtenAt: String
let content: String
let writerID: Int
let userID: Int
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.

writerID는 왜 이름을 id라고 지은 건가용?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

디티오가 바뀌어서 그거에 따라 수정해주었습니다!!

Comment on lines +10 to +17
protocol CommentProtocol: AnyObject {
func moreLabelDidTap(commentID: Int)
func replyIconDidTap(commentID: Int)
}

extension CommentProtocol {
func replyIconDidTap(commentID: Int) { }
}
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.

고능하다

showAllText: Bool,
isReplySheet: Bool
) {
if let _ = replyCount {
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.

이거 replyCount != nil 이렇게 해주어도 될 듯 해요 !

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.

고생하셧어요 , . . . . 애증의 더보기

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ㅠㅠㅠㅠㅠ..,더보기

func likeButtonDidTap()
}

final class QuestContentView: UIView {
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.

얘는 BaseView 사용하지 않은 이유가 잇나용

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

빼먹엇네요잉...

func moreLabelDidTap(commentID: Int) {
let updatedItems = dataSource.snapshot().itemIdentifiers.map { item -> CommentItem in
guard item.entity.commentID == commentID else { return item }
return CommentItem(entity: item.entity, showAllText: true)
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.

👍👍👍

Copy link
Copy Markdown
Collaborator

@dev-domo dev-domo left a comment

Choose a reason for hiding this comment

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

수고하셨습니다! Diffable 활용 대단하네요😯 코멘트만 확인 부탁드려요!


struct CommonQuestAnswerRepliesResponseDTO: Decodable {
let totalCount: Int
let comment: CommonQuestAnswerCommentResponseDTO
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.

comment도 여러 개 들어올 수 있지 않나요?

Copy link
Copy Markdown
Member Author

@y-eonee y-eonee May 19, 2026

Choose a reason for hiding this comment

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

하나의 댓글에 대한 답글 리스트 DTO여서 comment는 하나만 들어올 수 있습니다!!

}
}

func keyboardWillHide(duration: Double) {
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.

KeyboardHandleProtocol의 keyboardWillShow와 keyboardWillHide 메서드의 차이점이 키보드 높이뿐이어서 height 파라미터에 기본값을 0을 부여하면 두 메서드를 하나로 합쳐서 사용 가능할 것 같아요!

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

오!!!! 반영하겠습니다

@y-eonee y-eonee merged commit d24417a into develop May 19, 2026
1 check passed
@y-eonee y-eonee deleted the style/#428-댓글-ui branch May 19, 2026 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Style] 댓글 UI

3 participants