티스토리 뷰
<뇌 피셜로 이루어진 글 이므로 걸러서 읽기바랍니다.. 잘못된점 있으면 꼭! 알려주세요!!>
일단 결론은 LazyColumn안에 LazyColumn을 넣는게 아니다
LazyColumn안에 item을 여러개 넣을 수 있는 LazyListScope안에 또다시 LazyListScope를 넣는것임 그리고 그 LazyListScope에 댓글 대댓글을 item으로 넣는것
[Compose] LazyColumn안에 LazyColumn넣기, NestedScroll, Column 안에 LazyColumn넣기
이런식으로 게시판 화면을 만들고 싶었다 그래서 Column에 스크롤을 넣고 그 안에 댓글부분은 LazyColumn으로 넣었다 그랬더니 아래같은 오류가 나고 터졌다 java.lang.IllegalStateException: Vertically scrollabl
demat.tistory.com
이 글에서 마지막에 쓴 부분을 보면 대댓글을 위해서
댓글이 item으로 들어가니깐
댓글인 item안에 또 item으로 대댓글이 들어갈수는 없나? 라고 했는데 그거는 아니고
item을 여러개 넣을 수 있는 LazyListScope안에 또다시 LazyListScope를 넣고 거기에 댓글, 대댓글을 넣는 방식
https://stackoverflow.com/questions/71667299/how-to-build-a-tree-using-lazycolumn-in-jetpack-compose
How to build a tree using LazyColumn in Jetpack Compose?
In my jetpack-compose app, I'm building a comment tree, where the top level, and the leaves, are lists, that would be best to use LazyColumn. This is of the form: List<CommentNode> ... Commen...
stackoverflow.com
집으로 오는 셔틀버스 안에서 폰으로 뒤적..뒤적 거리다가 이런 글을 발견 역시 스택오버플로우에는 없는게없다
챗 gpt? 걔는 뭘몰라 스택오버플로우 뿐.
일단 가장 겉(상단 글 내용, 댓글 내용 모두가 있는 스크린 부분)
LazyColumn(modifier = Modifier.padding(16.dp, 0.dp)) {
item {
Column() {
BoardDetailHead(
postData = selectedPost.value!!,
userDataId = viewModel.userDataId
)
BoardDetailBody(postData = selectedPost.value!!)
Spacer(modifier = Modifier.size(20.dp))
Divider()
Spacer(modifier = Modifier.size(20.dp))
}
}
BoardDetailComments(
viewModel = viewModel,
commentList = commentList,
reCommentList = reCommentList
)
item {
Spacer(modifier = Modifier.size(height))
}
}
이렇게 생겼다
보면 다른애들은 다 item으로 감싸 있는데 BoardDetailComments얘만 item으로 감싸져 있지 않다

보면 item은 LazyItemScope이다 그러면 BoardDetailComments가 그냥 있는 이유는
BoardDetailComments자체가 LazyListScope이기 때문!
LazyListScope는 안에 item을 여러개 가질 수 있게된다 item은 LazyItemScope이다
private const val TAG = "BoardDetailComments"
fun LazyListScope.BoardDetailComments(
viewModel: BoardViewModel,
commentList : MutableList<CommentDto>
) {
commentList.forEach{
Log.d(TAG, "BoardDetailComments: 드로잉 LazyListScope추가")
Comment(commentData = it, viewModel = viewModel)
}
}
BoardDetailComments는 이렇게 생겼다(아.. 이름 새로 지어주고싶다 근데 안떠오른다)
댓글 리스트를 받아 forEach를 돌면서 Comment를 넣는다
엥 이러면 그냥 forEach로 Column하나씩 만드는거랑 뭐가다름 ㅋ?(맨밑에 그냥 Column으로 하는거랑 비교해보겟음)
fun LazyListScope.Comment(commentData: CommentDto, viewModel: BoardViewModel) {
val menuItemList : MutableList<CustomMenuItem> = mutableListOf()
menuItemList.apply {
add(CustomMenuItem("수정"){})
add(CustomMenuItem("삭제"){})
}
item{
Log.d(TAG, "Comment: 드로잉 댓글 ${commentData.comment}")
Column {
Row {
Spacer(modifier = Modifier.size(10.dp))
CommentContent(comment = commentData)
Row(
modifier = Modifier.weight(1f),
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.End
) {
if (viewModel.userDataId != commentData.normalUserId) {
ReCommentButton ({})
} else {
CommentMenuButton(menuItemList = menuItemList)
}
}
Spacer(modifier = Modifier.size(10.dp))
}
Spacer(modifier = Modifier.size(14.dp))
}
}
if(commentData.reCommentList!=null){
commentData.reCommentList!!.forEachIndexed { index, commentDto ->
ReComment(commentData.reCommentList!![index], viewModel, index==0)
}
}
}
보면 Comment또한 역시 LazyListScope이다 그냥 Composable이 아니다 그래서 @Composable어노테이션도 없다
댓글을 item으로 하나 넣는다(본 댓글은 하나고 거기 달리는 대댓글이 여러개니깐)
그 다음 만약 commentData에 reCommentList 즉 대댓글이 있다면 여기 또 ReComment들을 여러개 넣는다
ReComment는 LazyItemScope이므로 item으로 감싸서 넣는다 얘는 밑에서 한번 더 보겠다
Comment의 구조는 본 댓글 1개 item, 대댓글 item여러개 인 LazyListScope인것임
private const val TAG = "ReComment"
@Composable
fun LazyItemScope.ReComment(commentData: CommentDto, viewModel: BoardViewModel, isFirstReComment: Boolean) {
val menuItemList : MutableList<CustomMenuItem> = mutableListOf()
menuItemList.apply {
add(CustomMenuItem("수정"){})
add(CustomMenuItem("삭제"){})
}
Log.d(TAG, "ReComment: 드로잉 ${commentData.comment}")
Column (){
Row(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.width(30.dp)) {
if (isFirstReComment) {
Icon(
imageVector = MyIconPack.Childarrow,
contentDescription = "대댓글",
tint = Color.Unspecified,
modifier = Modifier.size(24.dp)
)
}
}
CommentContent(comment = commentData)
Row(
modifier = Modifier.weight(1f),
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.End
) {
if (viewModel.userDataId == commentData.normalUserId) {
CommentMenuButton(menuItemList = menuItemList)
}
Spacer(modifier = Modifier.size(10.dp))
}
}
Spacer(modifier = Modifier.size(14.dp))
}
}
ReComment는 이렇게 생겼다
ReComment는 LazyItemScope이다 왜냐면 대댓글 안에 또 여러개의 item들이 들어가야되는것은 없기때문에 그냥 LazyItemScope를 했다
LazyItemScope는 @Composable인듯함
암튼 구조를 그림으로 그려보면

이렇게 되는듯
이제 데이터를 넣고 로그 찍히는것을 보겠다
데이터는 아래와같다
val reCommentList: MutableList<CommentDto> = mutableListOf()
reCommentList.apply {
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "대댓글내용1",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "대댓글내용2",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "대댓글내용3",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "대댓글내용4",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
}
val reCommentList2: MutableList<CommentDto> = mutableListOf()
reCommentList2.apply {
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "2- 대댓글내용1",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "2- 대댓글내용2",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "2- 대댓글내용3",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "2- 대댓글내용4",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = true,
null
)
)
}
val commentList: MutableList<CommentDto> = mutableListOf()
commentList.apply {
add(
CommentDto(
commentId = 1,
normalUserId = 1,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "댓글내용1",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = false,
reCommentList
)
)
add(
CommentDto(
commentId = 1,
normalUserId = 2,
postId = 1,
festivalId = 1,
hostId = 1,
comment = "댓글내용2",
createdAt = testDate,
createdBy = "사용자 닉네임",
updatedAt = testDate,
depth = false,
reCommentList2
)
)
}
대강 댓글은 2개고 거기에 각각 대댓글은 4개씩임
로그 찍은것을 확인해보면

처음 게시글 들어갔을때임
(위에 한번 더 출력되는건 뭔지 모르겠네.. 이 글에서 살펴보는 LazyListScope랑은 관련없는 문제같긴한데 이또한 나의뇌피셜임)
일단 BoardDetailComments에서 for문 돌릴때마다 (Comment추가될때마다?) LazyListScope추가를 출력하도록 햇는데
LazyListScope가 두번출력됨 근데 밑에 출력되는걸 보면 댓글1만 로그가 찍히고 화면에 안보이는 대댓글이나 댓글2에 대해서는 로그가 안찍힘
즉 그리는거(컴포지션이라고 하나??)자체는 화면에 보여야만 그린다는것

그리고 살살 내려보면 화면에 대댓글이 보여지는 순간에 그려져서 로그가 찍힌다
그냥 Column으로 넣는거랑 뭐가 다른지 비교를 위해서 아래처럼 코드를 바꾸고 똑같은 데이터로 로그를 찍어보았다
제일 겉의 LazyColumn은 이렇다, items로 BoardDetailComments를 하나씩 넣는다
LazyColumn(modifier = Modifier.padding(16.dp, 0.dp)) {
item {
Column() {
BoardDetailHead(postData = selectedPost.value!!, userDataId = viewModel.userDataId)
BoardDetailBody(postData = selectedPost.value!!)
Spacer(modifier = Modifier.size(20.dp))
Divider()
Spacer(modifier = Modifier.size(20.dp))
}
}
items(commentList.size) { index ->
BoardDetailComments(
viewModel = viewModel,
comment = commentList[index]
)
}
item {
Spacer(modifier = Modifier.size(height))
}
}
BoardDetailComments는 이렇다
코멘트 컬럼 안에 본 댓글 넣고 리스트에 있는 대댓글을 for문 돌려서 넣는다
@Composable
fun BoardDetailComments(
viewModel: BoardViewModel,
comment: CommentDto
) {
Column() {
Comment(commentData = comment, viewModel = viewModel)
if (comment.reCommentList != null) {
comment.reCommentList!!.forEachIndexed { index, commentDto ->
ReComment(
commentData = commentDto,
viewModel = viewModel,
isFirstReComment = index == 0
)
}
}
}
}
ReComment는 이렇다
private const val TAG = "ReComment"
@Composable
fun ReComment(commentData: CommentDto, viewModel: BoardViewModel, isFirstReComment: Boolean) {
val menuItemList : MutableList<CustomMenuItem> = mutableListOf()
menuItemList.apply {
add(CustomMenuItem("수정"){})
add(CustomMenuItem("삭제"){})
}
Log.d(TAG, "ReComment: 드로잉 ${commentData.comment}")
Column (){
Row(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.width(30.dp)) {
if (isFirstReComment) {
Icon(
imageVector = MyIconPack.Childarrow,
contentDescription = "대댓글",
tint = Color.Unspecified,
modifier = Modifier.size(24.dp)
)
}
}
CommentContent(comment = commentData)
Row(
modifier = Modifier.weight(1f),
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.End
) {
if (viewModel.userDataId == commentData.normalUserId) {
CommentMenuButton(menuItemList = menuItemList)
}
Spacer(modifier = Modifier.size(10.dp))
}
}
Spacer(modifier = Modifier.size(14.dp))
}
}
로그를 확인해보자

이렇게(아니 이거 왜 두번찍히는거임???????) 댓글 1에 대해서 대댓글4가 화면에 보이지 않는 상황임에도 대댓글 4 까지 다 컴포지션 해서 들어간 모습

죄금 내려보면 이렇게 댓글2가 렌더링되는데 대댓글들이 모두 화면에 보이지도 않지만 일단 대댓글들이 다 같이 들어감
이게 BoardDetailComments자체는 item으로 들어갔기때매 화면에 보일때만 그려지는데 대댓글들은 그 안에 포함되어서 화면에 안보이지만 같이 들어가는 그런 현상인듯함!!
만약 대댓글이 100000개 막 이렇게 엄청 많아지면 아주 .. .. . . 좋지 않을듯?
앞에서봤던 방식으로 했을때 대댓글들이 화면에 진짜 나올때만 출력되는것과 다른모습...
암튼 결론은
LazyColumn 안에 LazyColumn을 넣으려고 하면 잘안된다
Nested LazyColumn은 안된다
대신 LazyColumn을 하나 두고 그 안에 item을 여러개 넣는다
만약 item안에 또 중첩해서 그 안에 item들을 더 넣고싶다면? item안에 item이 아니라!! LazyListScope안에 LazyListScope를 넣어서 그 안에 item을 여러개 넣는 방식을 쓰자
끝!
'공부 > Android' 카테고리의 다른 글
[Compose] 데이터를 부르는 방법에 대한 고민 (0) | 2023.08.13 |
---|---|
[플러터] iframe에서 데이터 가져오기 webViewx (0) | 2023.08.06 |
[Compose] Text가 너무 길어서 맨 끝의 Icon이 보이지 않을때, 잘릴때 (0) | 2023.08.03 |
[Compose] LazyColumn안에 LazyColumn넣기, NestedScroll, Column 안에 LazyColumn넣기 (0) | 2023.08.03 |
[Compose] 화면 따라다니는 Footer 만들기(Composable 높이 구하기) (0) | 2023.08.03 |