Skip to content

Conversation

@KYM-P
Copy link
Collaborator

@KYM-P KYM-P commented Oct 29, 2025

PR 개요

이슈 번호: 1129

PR 체크리스트

  • Code convention을 잘 지켰나요?
  • Lint check를 수행하였나요?
  • Assignees를 추가했나요?

작업사항

  • 버그 수정
  • 신규 기능
  • 코드 스타일 수정 (포맷팅 등)
  • 리팩토링 (기능 수정 X, API 수정 X)
  • 기타

작업사항의 상세한 설명

동아리 화면에 딱딱하던 스크롤을 부드럽게 바꾸었습니다.
알림 클릭 시 발생하는 scroll 이벤트도 새로운 logic 에 맞도록 모두 수정했습니다.
(toolbar 를 전부 스크롤 한 후 메인 화면을 스크롤로 넘어가는 단계에서 한번 스크롤이 막히는 현상이 존재)

논의 사항

식단 화면의 스크롤과는 logic 이 비슷하지만 다릅니다.

식단

  • 고정된 크기의 toolBar
  • 위로 가도록(손 방향은 아래로) 스크롤 시 toolbar 가 먼저 소진
  • toolBar 위치는 스크롤을 감지하지 않음

동아리

  • 가변 크기의 toolBar (즉 측정 단계 필요)
  • 위로 가도록(손 방향은 아래로) 스크롤 시 toolbar 대신 메인 스크롤이 먼저 소진
  • toolBar 위치도 스크롤을 모두 감지해야함

이에 다음과 같은 변화가 필요했습니다.

  • 위쪽 스크롤 동작 변경 -> nested Scroll 수정
  • 가변 크기의 toolBar -> 전체 toolBar 크기를 측정하는 단계
  • toolBar 위치도 스크롤을 모두 감지해야함 -> Box 와 offset 을 통한 scroll효과 대신 LazyColumn 과 height 를 통한 scroll효과

[전체 toolBar 크기를 측정하는 단계] 부분

Layout 을 사용해 measurable 로 측정할까 했지만
toolbar 의 내부 요소가 너무 방대, 최소 1회성 단발 측정만 필요, recomposition 마다 측정이 다수 발생할 수 있음
등의 문제 상황이 있어 onSizeChangedModifier.then 으로 단발성 측정만 시도했습니다.

[Box 와 offset 을 통한 scroll효과 대신 LazyColumn 과 height 를 통한 scroll효과] 부분

scroll 관련 로직은 nestedScroll 에 모두 정의되어 있어 nestedScroll 을 통하는 scroll 만 사용해야 합니다.
근데 nestedScroll 에 스크롤 정보를 넘겨주기 위해서는 LazyColumn 이나 Column(스크롤가능) 의 컴포넌트만 가능합니다.
(Box 불가능)
그렇기에 scrollState 를 만들지 않아도 작동하는 LazyColumn 으로 구성하였고
offset 이 아닌 reverseLayout = true 옵션(역순 구조화)을 통해 화면을 바닥 고정으로 하여 스크롤 시 상단 부분이 사라지도록 했습니다.
(옵션을 빼면 하단 부분부터 사라집니다.)
이후 tab 목록을 같이 넣으려 했으나 해당 옵션으로 역순 구조화 덕분에 그리는 순서(item)를 역순으로 구조화 해야하니 코드 가독성이 떨어질 것 같다 그냥 LazyColumn 을 하나 더 만들어 처리했습니다.

그 밖에도 알림을 누를 시 해당 페이지로 이동(스크롤)하는 기능 을 위해 스크롤 부분도 수정이 되었습니다.

다시 생각해도 코드가 너무 개판이라
압축 혹은 가독성을 높일 수 있을 거 같은 요인은 언제나 말씀해주세요.

스크린샷

KakaoTalk_20251029_173657853.mp4

기왕이면 직접 pull 해서 사용해보세요

추가내용

  • develop, sprint 브랜치를 향하고 있습니다
  • production 브랜치를 향하고 있습니다

KYM-P added 4 commits October 28, 2025 20:37
Add club scroll test
Change scroll event
Feat ktlint
Fix scroll event to handle new scroll logic
@KYM-P KYM-P requested a review from a team as a code owner October 29, 2025 06:43
@github-actions github-actions bot added the refactor Code refactoring label Oct 29, 2025
Feat ktlint
@KYM-P KYM-P changed the title Refactor/#1129 club detail scroll [Koin Project][Refactor] 동아리 상세 화면 스크롤 logic 변경 Oct 29, 2025
Copy link
Member

@kongwoojin kongwoojin left a comment

Choose a reason for hiding this comment

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

Recomposition이 너무 많아요
스크롤 할때마다 10씩 올라가는데, 무조건 성능 문제 생깁니다

@KYM-P
Copy link
Collaborator Author

KYM-P commented Oct 29, 2025

Recomposition 이 많이 발생하는 이유는
scroll 을 직접적으로 px 단위로 깎으면서 height 를 재 조정하여 보여지고 있으며,
심지어 해당 px 단위 사이를 animationPx 를 통해 50ms 마다 중간값을 보간해주고 있습니다.
(이것만 해도 스킵될 수도 있지만 얼추 50ms 단위로 recomposition...)
그렇기에 한번 손을 움직일 때 마다 많은 양이 recomposition 될 수 밖에 없는 것 같습니다.
마찬가지로 같은 방법을 사용하는 dining 에서도 비슷하게 찍히고 있습니다.
(기본적인 Column 등의 scroll 구현도 집계만 안될 뿐이지 이런 방식이 아닐까요..?)

개인적으로는 자연스러운 scroll 을 위한 필수 불가결한 문제라고 생각합니다.
recomposition 이 안되면서 커스텀 scroll 이 되는 방법은 따로 없을 거 같습니다.(일단 더 찾아볼게요)
이 부분을 의식해 전체를 하나의 LazyColumn 으로만 만드는 방법도 있긴 한데 이러면 각 탭의 스크롤 정보를 저장할 수 없습니다.
이 방법이 아니면 다시 기존 방법의 스크롤로 돌아가는 방법 뿐인 거 같습니다.

그래서 주의깊게 볼 부분은 recompostition 횟수보단
recomposition 마다 같이 계산되는 remember 하지 않은 부분을 찾아내서 줄이는 방면을 봐야 할 거 같습니다.
아직까지는 시뮬에서도 어느정도 잘 돌아가니 큰 문제는 없어 보입니다만. 이 부분은 저도 한번 다시 검토하겠습니다.

@kongwoojin
Copy link
Member

Recomposition 이 많이 발생하는 이유는 scroll 을 직접적으로 px 단위로 깎으면서 보여지고 있으며, 심지어 해당 px 단위 사이를 animationPx 를 통해 50ms 마다 중간값을 보간해주고 있습니다. (이것만 해도 스킵될 수도 있지만 얼추 50ms 단위로 recomposition...) 그렇기에 한번 손을 움직일 때 마다 많은 양이 recomposition 될 수 밖에 없는 것 같습니다. 마찬가지로 같은 방법을 사용하는 dining 에서도 비슷하게 찍히고 있습니다. (기본적인 Column 등의 scroll 구현도 집계만 안될 뿐이지 이런 방식이 아닐까요..?)

개인적으로는 자연스러운 scroll 을 위한 필수 불가결한 문제라고 생각합니다. recomposition 이 안되면서 커스텀 scroll 이 되는 방법은 따로 없을 거 같습니다.(일단 더 찾아볼게요) 이 부분을 의식해 전체를 하나의 LazyColumn 으로만 만드는 방법도 있긴 한데 이러면 각 탭의 스크롤 정보를 저장할 수 없습니다. 이 방법이 아니면 다시 기존 방법의 스크롤로 돌아가는 방법 뿐인 거 같습니다.

그래서 주의깊게 볼 부분은 recompostition 횟수보단 recomposition 마다 같이 계산되는 remember 하지 않은 부분을 찾아내서 줄이는 방면을 봐야 할 거 같습니다. 아직까지는 시뮬에서도 어느정도 잘 돌아가니 큰 문제는 없어 보입니다만. 이 부분은 저도 한번 다시 검토하겠습니다.

Recomposition이 일어나더라도, recomposition이 필요한 컴포넌트를 제외하고는 skip이 되어야하는데, 지금은 그렇지 않은 것 같습니다.
성능 문제도 크게 안 느껴질수도 있지만, 실제로 기기마다 편차가 존재하는 부분이고, 코인 사용자 통계를 봤을때는 낮은 GPU 성능을 가진 폰도 많은 상황에서 문제가 없다고 단정하기는 힘들어보입니다.

@KYM-P
Copy link
Collaborator Author

KYM-P commented Oct 29, 2025

Recomposition이 일어나더라도, recomposition이 필요한 컴포넌트를 제외하고는 skip이 되어야하는데, 지금은 그렇지 않은 것 같습니다. 성능 문제도 크게 안 느껴질수도 있지만, 실제로 기기마다 편차가 존재하는 부분이고, 코인 사용자 통계를 봤을때는 낮은 GPU 성능을 가진 폰도 많은 상황에서 문제가 없다고 단정하기는 힘들어보입니다.

그럼 우선 적용은 보류로 하고
recomposition 마다 호출되는 계산 부분을 집중적으로 깎는 방향으로 가도 될까요?
Px 로 height 를 깎으면서 하는 방법 없이 기본 Column 요소 만으론 지금 개선 전 방식 말고는 떠오르지 않을 거 같습니다.

@KYM-P KYM-P self-assigned this Oct 29, 2025
Delete unremember variable to skip recomposition
@KYM-P
Copy link
Collaborator Author

KYM-P commented Nov 13, 2025

Unremember 변수 수정

  • 동아리 상세 화면에서 일반 val(계산 보유), var로 선언한 모든 변수를 remember 화 시켰습니다. (skip 부분 증가)
    동아리 tabList, 동아리 qnaList 등등

image 에서 painter 쓰는 부분을 모두 imageVector 로 수정

  • 복사 아이콘을 Image( painter = ) 로 사용중이였는데 이 부분에서 recomposition 이 계속 발생했습니다.(Unstable)
    이 부분을 ImageVector 로 바꾸어 stable 상태로 바꾸었습니다. (recomposition 대상 제외)
스크린샷 2025-11-13 231505 스크린샷 2025-11-14 001847

최종적으로 height 를 조정하는 LazyColumn 말고는

skip 혹은 recompostion 대상 제외를 하도록 변경했습니다.

집계
스크린샷 2025-11-14 002518

@KYM-P KYM-P requested a review from kongwoojin November 14, 2025 00:21
Change listof variable to remember persistentlist
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource

fun clubDetailScrollConnection(
Copy link
Contributor

Choose a reason for hiding this comment

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

공통으로 사용 가능한 컴포넌트는 core 모듈쪽으로 빼는거는 어떨까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

koin project refactor Code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants