[Flutter]Scrolling과 Sliver를 파헤치며

한상욱·2024년 9월 2일
0

Flutter

목록 보기
21/26
post-thumbnail

들어가며

Scroll UI를 이용하면 사용자에게 훌륭한 UX를 제공할 수 있습니다. 아무래도 정적인 화면보다는 Scroll UI에 익숙하기에 사용자는 자연스럽게 아래로 스와이프하며 앱을 탐색할 것입니다.

오늘은 Flutter에서의 Scrolling 그리고 이러한 Scrolling을 더욱 특별하게 만들어줄 수 있는 Sliver에 대해서 알아보겠습니다.

Scrolling과 ViewPort

사실, Flutter는 이미 기존의 내재된 위젯을 통해서 Scroll 기능을 쉽게 구현할 수 있습니다. 예를 들어, 자식 위젯의 Scroll을 제공하는 SingleChildScrollView, 아이템 리스트를 보여주는 ListView, 특정 Grid를 보여주는 GridView가 대표적입니다. 또한, 이러한 아이템 배열의 크기만큼 Infinity Scrolling을 제공해주는 ListView.builder, GridView.builder도 존재합니다.

우리는 위에서 언급된 위젯을 통해서 Scroll과 관련된 비즈니스 로직을 작성하지 않아도 위젯이 알아서 해당 Scroll을 제공하죠. 그렇지만, 요구사항에 따라서 다양한 Scroll 효과를 구현해야 하는 경우가 생길 수 있습니다.

예를 들어, AppBar가 Scroll 이벤트에 따라서 동적으로 움직이거나 Parellex Scrolling이 있을 수 있습니다. 이러한 애니메이션들을 기본 제공되는 Scroll 위젯들만을 이용해서 구현을 하게 되면, ListView 내부에서 새로운 ListView와 같은 Scroll 위젯들을 선언하게 되고 자연스럽게 ShrinkWrap, NeverScrollableScrollPhysics()등의 내용을 접하여 사용하게 됩니다.

하지만, 이는 좋지 못한 방법이라고 할 수 있습니다.

왜?

Flutter는 Scroll 위젯에서 스크롤되는 영역이 실제로 사용자에게 보여지는 부분을 ViewPort라고 정의하고, 해당 ViewPort에서 위젯들을 보여주게 됩니다. 만약 이러한 위젯들 사이에 새로운 Scroll 위젯이 존재한다면 ViewPort내부에 새로운 ViewPort가 존재하게 되고, Flutter는 제대로 Scrolling Lendering을 수행하지 못합니다. 끊임없이 dimension들을 인지하기 때문입니다.

이러한 에러를 수정하기 위해서 Flutter 에러 메시지 또는 Stack Overflow와 같은 커뮤니티등에서 제안하는 shrinkWrap을 true로 전달하고 NeverScrollableScrollPhysics()를 지정하는 것을 통해 에러를 수정하곤 하는데요. 이렇게 하면 어떻게 에러가 사라지고 정상적으로 UI가 렌더링 되는 것일까요?

위에서 언급된 솔루션은 사실 Flutter가 최고 수준의 ViewPort에서 인지하는 ViewPort를 강제로 하나의 위젯인 것처럼 인식하게 만들어버립니다. 그렇기에 Flutter에서 아무런 에러가 발생하지 않고 정상적으로 Scroll UI가 동작하는 것이죠. 사실, 이러한 과정이 아무런 성능적인 문제가 없다고 인식될 수 있겠지만, ViewPort 내부에 존재하는 위젯의 크기가 커짐에 따라서 프레임이 깨지거나 삭제되거나 버벅거리게 되는 것이죠. 왜냐하면 ShrinkWrap은 강제하는 것에 많은 비용이 들기 때문입니다.

이러한 문제를 어떻게 해결할 수 있을까요? 이를 위해서 Flutter에는 Sliver가 존재합니다.

Sliver

Flutter 공식문서에서는 Sliver를 스크롤 가능한 영역의 일부분이라고 소개하고 있습니다. ListView 위젯이 있다고 하겠습니다. ListView 위젯에는 여러가지 아이템들이 존재하고, 그러한 아이템들이 모여서 ListView를 이루고 이러한 ListView가 할당받은 영역이 ViewPort입니다. Sliver는 스크롤 가능한 영역의 일부분이라고 했으니 여기서는 ListView를 구성하는 아이템 하나하나가 Sliver라고 할 수 있고, 이러한 Sliver를 하나로 모으면 Slivers 스크롤 가능한 영역이 됩니다. 이러한 Slivers라는 표현은 CustomScrollView와 같은 위젯에서 스크롤될 위젯들을 전달하는 배열 프로퍼티에서 주로 볼 수 있습니다.

SliverList와 ListView의 차이

사실, 위 두 위젯에 대한 차이에 대해서 조금 설명이 필요합니다. 이를 통해서 Sliver에 대한 개념을 명확하게 알 수 있을 것입니다.

ListView와 SliverList는 정확하게 동일한 역할을 하지만 정체가 살짝 다릅니다. ListView와 GridView는 동시에 사용하면 각각 독립적인 ViewPort를 갖게 됩니다. 따라서, 동시에 List, Grid를 하나의 ViewPort로 보여주기 위해서는 ShrinkWrap을 이용하게 되는데, 역시나 이는 비용적인 측면에서 좋지 못합니다.

이를 가능하게 하는 다른 방법이 바로 SliverList, SliverGrid를 이용하는 것입니다. SliverList는 ListView와 동일한 UI를 표현하게 됩니다. 다만, SliverList는 위젯이 아니라 Sliver입니다. 그렇기에 ViewPort내에서 스크롤 가능한 하나의 영역으로 표현할 수 있습니다.

ListView는 위젯이고, SliverList는 Sliver라는 것이죠. GridView와 SliverGrid도 마찬가지입니다.

CustomScrollView

이제, CustomScrollView에 대해서 알아보죠. 위에서 언급한 것들처럼 Flutter가 제공하는 위젯으로는 ViewPort를 원하는대로 정의할 수 없습니다. 하지만 CustomScrollView는 Sliver를 조합하여 사용자가 직접 ViewPort를 정의할 수 있기에 이를 이용하면 나만의 특별한 ViewPort를 만들어낼 수 있죠.

AppBar에도 특별한 효과를 주고 싶다면 우리는 SliverAppBar를 이용해서 AppBar도 Sliver로 표현하여 훌륭한 애니메이션을 제공할 수 있습니다.

지금은 가장 기본적인 SliverAppBar이지만, 프로퍼티를 통해서 다양한 효과를 표현할 수 있습니다.

마지막으로, 이 외에 ViewPort가 아닌 일반 위젯을 함께 렌더링 시켜야 되는 경우에는 위젯을 Sliver로 변경시켜주어야 합니다. 그러기 위해서는 SliverToBoxAdapter를 이용해야 합니다. CustomScrollView에 ViewPort가 아닌 위젯은 모두 SliverToBoxAdapter를 사용하죠.

아래의 예시는 FlutterLogo를 SliverToBoxAdapter로 감싸 CustomScrollView에 전달한 것입니다.

profile
자기주도적, 지속 성장하는 모바일앱 개발자가 되기 위해

0개의 댓글