티스토리 뷰

 

많은 사람들이 shrinkWrap을 사용하면 성능이 크게 저하될 것이라고 걱정하지만, 정작 shrinkWrap의 정확한 동작 원리는 잘 모르는 경우가 많습니다. 이러한 생각이 플러터 개발자들 사이에서 정설처럼 받아들여지는 이유는 대부분 ListView나 GridView 같은 스크롤 위젯에서 자식에게 별도의 제약 조건을 걸지 않은 채 중첩 스크롤 안에서 shrinkWrap을 사용하거나, 부모에 최대 크기 제약이 없는 경우 ListView를 단순 Column처럼 사용하기 때문입니다.

 

“엥? 원래 높이에 대한 제약이 없는 상태에서 쓰는 거 아냐?”

 

네, 그 생각은 완전히 틀리셨습니다.

플러터 팀에서는 그럴거면 Column을 쓰라고 하지 ListView를 Column처럼 쓰게 만드려고 shrinkWrap을 만든게 주요 목적이 아니거든요. 사람들이 계속 그렇게 쓰려고 하니까 편의상 경고를 하면서 대충 알려주는거에 가깝지. 근데 플러터 팀에서 경고만 하니까 그런 사람들이 핵심 옵션의 기능 자체를 모르고 자꾸 엄청나게 왜곡해서 악의적으로 퍼뜨리는 상황이 발생하는거죠. 😅

 

결국 shrinkWrap = 😡 극심한 성능 저하(?)

 

라는 편견만을 기반으로 한 잘못된 상식이 만들어진겁니다.


하지만 사실 shrinkWrap 자체는 화면에 보이는 항목만 빌드하고 렌더링하는 Lazy Building 특성을 전혀 해치지 않습니다. 그 이유는 shrinkWrap이 단지 스크롤 위젯의 Viewport 레이아웃 크기 계산 방식만 바꾸기 때문입니다. (이에 대한 오버헤드는 솔직히 매우 경미하거나 체감되지 않습니다.)

그럼에도 불구하고, 어떤 사람들은 여전히
"응? 잘 모르겠는데 어쨌든 성능에 영향이 클 거야"
라고 생각할 수 있습니다. 하지만 조금만 더 이해하면, 이런 걱정은 대부분 잘못된 편견임을 알 수 있습니다.

 

많은 사람들이 본능적으로 경험적으로 shrinkWrap은 무조건 사용하면 안 된다고 말하는데, 사실 이는 플러터의 렌더링 파이프라인 구조를 제대로 이해하지 못한 상태에서, 다른 사람에게 자랑하거나 우월감을 느끼기 위해 하는 말에 가깝습니다. 플러터 팀에서 shrinkWrap을 소개할 때 항상 잘못 사용하지 말라고 강하게 경고를 하거든요. 그래서 사람들이 회의적일 수 밖에는 없긴 합니다.

 

하지만,

 

여러분, 한번 생각해보세요. 플러터의 대부분 스크롤 위젯은 무한히 커지려는 특성을 가지고 있습니다. 내부 아이템들의 높이를 모두 합쳐도, 별도의 제약이 없으면 스크롤 위젯은 항상 부모의 크기를 채우려고 하죠. 왜냐면 레이아웃 계산 상으로는 그게 더 편하고 스크롤 가능한 제스처 영역을 개발자가 일일히 수동으로 정의할 필요가 없으므로 관련 버그 발생률을 줄일 수 있겠죠.

 

shrinkWrap false

 

위 이미지에서 초록색 영역은 실제 내부 아이템들의 총 높이이고 빨간색 영역은 스크롤 위젯의 레이아웃 크기이면서 동시에 파란색 영역은 부모 크기입니다. 해당 이미지대로 shrinkWrap가 활성화되어 있지 않다면 그냥 부모 크기로 자신의 레이아웃을 계산합니다.


하지만 특수한 상황에서는, 이 크기를 무한적으로 확장하려는 특성 그 자체가 문제를 일으킬 수 있습니다.

그래서 플러터는 shrinkWrap라는 옵션을 제공하며, 이를 사용하면 스크롤 위젯이 자신의 렌더링 아이템 높이를 기준으로 최대한 자신의 크기를 정의합니다. 즉, 부모 크기가 우선이 아니라 콘텐츠 크기를 우선으로 계산하는 방식으로 동작합니다. 옵션 이름 그대로 Shrink Wrap(축소하고 감싸다)의 뜻과 거의 비슷하게 동작을 하는 겁니다.

 

shrinkWrap true

 

위 이미지와 같이요.

 

따라서 Column과 같이 내부 아이템의 크기를 제한하지 않는 레이아웃 위젯에서는 shrinkWrap을 사용해 어느 정도 문제를 해결할 수 있습니다.

하지만 조금만 생각해보면 답이 곧 명확합니다. Column 안에 자신의 크기를 가지려는 shrinkWrap이 활성화된 스크롤 위젯을 넣으면, 스크롤 위젯의 아이템 전체 크기가 곧 Viewport의 크기가 되어 Lazy Building을 위한 레이아웃 계산이 제대로 수행되지 않습니다. 즉, 의도라기 보다는 그에 대한 심각한 부작용입니다. 당연하게도 제약을 안 걸어놓으니 끝없이 커지는 거예요.

 

하지만 그 부작용 조차도 부모가 자식의 크기를 강제하는 경우는 전혀 다릅니다. 아무리 shrinkWrap가 활성화된 상태에서도 Viewport 크기가 부모를 절대 넘지 못하거든요. 따라서 Lazy Building가 제대로 동작하는거죠. 이에 대해 유용한 경우를 간단히 말하자면, 아이템들의 총 높이가 Viewport 크기보다 작을 때에 그 수치까지 정확하게 알아야할 때, 마지막 아이템이 어디에 위치하고 그것에 따라 레이아웃을 수행해야할 때, 뭐 흔히 앱 개발에서는 스크롤뷰의 높이에 따라서 동적으로 배경 색의 높이를 지정해야 할때 등, 평범하고도 꽤 유용하게 사용될 수 있겠습니다. (이것 말고도 더 있습니다.)

 

그래서 대부분의 사용 사례에서는 그렇게밖에 사용할 수 없고, 사용자들은 큰 성능 저하를 경험하며 커뮤니티나 다른 사람들에게 “절대로 사용하지 마라, 안티 레이아웃 옵션이다”라는 식으로 전파하게 됩니다.

 

솔직히 그것이 사실이 아니라는 것을 아는 사람들은 그 말에 아, 정확히 잘 모르는구나~ 하면서 그저 분쟁을 일으키기 싫어서 넘어가는 경우가 많습니다. 그래서 사람들이 계속 그렇게 믿게 되는 거죠. 😅

 

하지만 사실은, 플러터에서나 문서에서나 공식적으로 shrinkWrap이 참일 경우 무조건적으로 모든 아이템들을 빌드한다. 라고 명시되어 있지 않습니다. 믿을 수 없다면 SDK 내부 소스 코드를 봐보면 되겠죠. 역시 성능에 크게 문제가 되는 부분은 딱히 없는 것을 볼 수 있습니다.

 

 

shrinkWrap property - ScrollView class - widgets library - Dart API

bool shrinkWrap final Whether the extent of the scroll view in the scrollDirection should be determined by the contents being viewed. If the scroll view does not shrink wrap, then the scroll view will expand to the maximum allowed size in the scrollDirecti

api.flutter.dev

Shrink wrapping the content of the scroll view is significantly more expensive than expanding to the maximum allowed size because the content can expand and contract during scrolling, which means the size of the scroll view needs to be recomputed whenever the scroll position changes.

 

실제 플러터 공식 문서를 보면 "스크롤 내부 아이템들의 콘텐츠 크기가 동적으로 변할 때 전체 크기를 재계산해야 해서 비용이 많이 든다" 라고 명시되어 또 초보자들을 혼란스럽게 하고 shrinkWrap는 성능 저하에 엄청난 녀석이구나! 하면서 잘못 학습시키게 만듭니다.

 

그런데 평소에도 경우에 따라 부모 제약이나 화면 회전, 크기 변경 등으로 ScrollView 크기가 변하면, Viewport와 내부 아이템 모두 다시 레이아웃됩니다.

 

이건 shrinkWrap를 사용하든 안사용하든 완전히 동일한 현상이거든요. 다만 저 문서에서 언급 하는 것은 "내부의 아이템들의 크기를 모두 알아야지 내 자신의 크기를 알 수 있기 때문에 그거 계산하는데 Layout Pass 쪽에 오버헤드가 좀 있어. 심지어 스크롤 위젯이 무한하게 확장 가능하다면 비용이 엄청 커!" 라는 것 뿐입니다. 무조건적으로 초기에 모든 아이템을 빌드한다. 라는게 절대 아니에요. 심지어 이런 오버헤드조차도 Lazy Building을 해치지 않은 상황에서는 일반적인 경우와 별 차이가 없죠.

 

근데 문서에서는 최대한 모든 정보를 담으려도 하다 보니, 극단적으로 아이템들의 높이가 달라지거나 하는 등의 솔직히 살면서 거의 보지도 못하는 현상을 해명하고 있으니까, 입문자들이 더 혼란스러워 하는 것입니다. 애당초 저건 일반적인 SDK 사용자들이 보라고 만든게 아니거든요.

 

실제로도 Bounded Constraint 환경에서 테스트를 해본다면 Lazy Building 아주 아주 정상적으로 잘 동작하는 것을 볼 수 있습니다. 기껏해야 계산 방법이 달려져서 생긴 약간의 오버헤드 정도겠지만... 그런 근거 없는 말과는 달리 복잡한 레이아웃에서도 저는 전혀 느끼질 못합니다. 벤치마크를 한번 돌려보세요. 솔직히 수치로도 인지할 수 있는 수준의 차이는 없습니다. 애당초 플러터 SDK에 공식 기여해본 입장에서 조금은 말씀드릴 수 있는 것은 성능에 광적으로 집착하는게 플러터 개발자들입니다. 아니 그쪽은 SKSL 코드에 if문 하나 걱정하는 사람들입니다. 따라서 체감상 성능에 크게 영향을 주는 기능 자체를 넣지 않을 수 밖에 없습니다.

 

심지어는 그 엄청나게 간단할 거 같은 디버그용 print에서도 비동기를 위한 Future, 객체 지향 언어 등에서 오버헤드가 발생합니다. 그렇다고 아예 사용하지 않는 것은 아니잖아요? 상황에 따라 적절하게 사용하는 겁니다.

 

그래서 저는 사람들이 무조건적으로 과한 반응을 내비치는 것은 개인적으로는, 그 반응이 다소 너무나도 과하다고 생각합니다.

저한테는 옵션의 진정한 활용법을 모르는 채 그저 어디서 들은 근거와 생각으로 무지성 비판만 하는 것은 참 아쉬운 일이에요.

 

그리고 플러터 팀이 성능이 안좋은 식으로만 사용하라고 괜히 shrinkWrap을 만들고 아직까지도 deprecated 하지 않는걸까요?

 

아뇨, 절대 아닙니다. 충분히 다른 상황에서는 유용하게 사용될 수 있어서에요. 기능은 한 사람을 위해서만 있는 것이 절대 아니니까요.


예를 들어, 저는 flutter_infinite_scroll_pagination에서 Lazy Building 기능을 해치지 않으면서도 체감 성능 저하 없이 shrinkWrap을 활용해 기존 infinite_scroll_pagination 사용성을 크게 개선했습니다. shrinkWrap 덕분에 오히려 더 안정적으로 레이아웃을 계산할 수 있었어요. 애당초 Viewport 크기 이하인 상황에서의 아이템들의 총 높이를 구해야 정확하게 인디케이터가 어디에 위치해야 하는지를 알 수 있거든요. ScrollController ScrollPosition에서 그런 정보는 제공하지 않습니다. 따라서 shrinkWrap을 사용합니다.

 

따라서 오히려 이로운 역할을 할수도 있는 shrinkWrap을 무조건적으로 멀리하고 배척하는 그 태도는 오히려 자신의 시야를 과도하게 좁히는 것이라고 저는 생각합니다.
정상적이지 않은 상황에서 발생한 shrinkWrap의 성능 문제만을 근거로 “무조건 나쁘다”고 믿는 것은, 사실상 종교와 신념 수준에 가깝습니다. 되려 안타까운 느낌이 듭니다. 다만 물론 여러분들 모두가 그러지는 않겠지만 그런 사람들이 아직도 많이 있다는 것이죠.

 

일부 사례 때문에 그렇게 학습했다면 어쩔 수 없지만, 논리 없이 비관적으로 바라보는 태도는 개선할 필요가 있습니다. 대부분의 플러터 개발자는 솔직히 SDK의 레이아웃 동작 원리를 온전히 이해하지 못하는 경우가 많으므로, 제 개인적으로는 새로운 관점으로 기술을 바라보면 더 좋지 않을까 생각이 들고.

 

결론적으로, 모든 기능은 이유가 있어서 존재한다고 생각합니다.
shrinkWrap 또한 올바른 상황에서 사용하면 충분히 가치 있는 도구와 옵션입니다. 편견을 좀 가지지 말았으면 합니다.

 

개인적으로는 문서는 성경처럼 읽는게 아니라 제대로 이해하는 것이 가장 중요하단 것을 많은 사람들이 깨달았으면 합니다.

 

이 글을 읽어주셔서 감사합니다. (꾸벅)

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함