개발노트

34. [Flutter] CustomScrollView 위젯 본문

앱 개발/Flutter

34. [Flutter] CustomScrollView 위젯

mroh1226 2023. 10. 5. 17:32
반응형

CustomScrollView

  • CustomScrollView는 Flutter에서 스크롤 가능한 컨텐츠를 구축하고 사용자 정의 스크롤 동작을 구현하는 데 사용되는 위젯입니다. CustomScrollView는 스크롤을 통해 여러 슬리버(slivers)를 관리하고 각 슬리버가 다른 레이아웃을 가질 수 있도록 해줍니다. 슬리버는 스크롤 가능한 영역 내에서 다양한 위젯 및 레이아웃을 정의하는 데 사용됩니다.

  • CustomScrollView를 사용하면 다음과 같은 장점이 있습니다:
    • 다양한 레이아웃 및 위젯 조합: 여러 슬리버를 사용하여 다양한 위젯 및 레이아웃을 조합할 수 있으므로 복잡한 UI를 구축할 때 유용합니다.
    • 스크롤 제어: 슬리버 간에 스크롤 동작을 제어할 수 있으므로 스크롤 가능한 영역을 사용자 지정할 수 있습니다.
    • 확장 가능한 헤더 및 푸터: 확장 가능한 앱 바, 헤더, 푸터를 만들 때 유용하게 사용됩니다.

  • CustomScrollView를 사용하려면 일반적으로 다음 단계를 따릅니다:
    • CustomScrollView를 생성합니다.
    • slivers 속성을 설정하여 여러 슬리버를 정의합니다.
    • 각 슬리버를 SliverAppBar, SliverList, SliverGrid 등의 슬리버 위젯으로 설정합니다.
    • 각 슬리버 위젯의 속성을 조절하여 원하는 동작 및 레이아웃을 구현합니다.
    • 예를 들어, SliverAppBar를 사용하여 확장 가능한 앱 바와 헤더를 만들거나 SliverList 및 SliverGrid를 사용하여 스크롤 가능한 리스트 또는 그리드를 만들 수 있습니다.
    • CustomScrollView는 다양한 유형의 슬리버를 조합하여 복잡한 스크롤 가능한 UI를 만들 때 사용되며, Flutter에서 고급 UI를 구축하는 데 필수적인 위젯 중 하나입니다.

예시.

import 'package:flutter/material.dart';

class UserProfileScreen extends StatefulWidget {
  const UserProfileScreen({super.key});

  @override
  State<UserProfileScreen> createState() => _UserProfileScreenState();
}

class _UserProfileScreenState extends State<UserProfileScreen> {
  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      physics:
          const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
      slivers: [
        SliverAppBar(
          backgroundColor: Colors.teal,
          floating: true, //당기면 같이 스크롤됨
          stretch: true, //당기기 가능여부: true
          pinned: true, //위에 작아진 채로 고정됨
          snap: true, //스크롤하면 AppBar가 stretch된 상태로 한번에 나타나거나 사라짐
          collapsedHeight: 60, //AppBar 크기
          expandedHeight: 200, //확장된 AppBar 크기
          flexibleSpace: FlexibleSpaceBar(
            stretchModes: const [
              StretchMode.blurBackground, //당기면 블러처리됨
              StretchMode.zoomBackground, //당기면 Zoom됨
            ],
            centerTitle: true,
            title: const Text('Profile'),
            background: Image.asset(
              "assets/images/img_guitar.png",
              fit: BoxFit.cover,
            ),
          ),
        ),
        const SliverToBoxAdapter(
          //List가 아닌 일반적인 위젯을 Sliver에 추가할때 사용
          child: CircleAvatar(),
        ),
        SliverFixedExtentList(
            //CustomScrollView 안에 List를 만드는 위젯
            delegate: SliverChildBuilderDelegate(
                //List안에 들어갈 위젯 작성
                childCount: 8, //자식 갯수: 10
                (context, index) => Container(
                      alignment: Alignment.center,
                      color: Colors.teal[100 * (index % 9)],
                      child: Text("index: $index"),
                    )),
            itemExtent: 100), //item의 높이: 100
        SliverPersistentHeader(
            //이 위젯으로 Header를 추가할 수 있음
            pinned: true, // pinned를 해줘야 header가 안사라지고 고정됨
            delegate: CustomDelegate()),
        SliverGrid(
            //List 안에 Grid를 만드는 위젯
            delegate: SliverChildBuilderDelegate(
                childCount: 36,
                (context, index) => Container(
                      alignment: Alignment.center,
                      color: Colors.teal[100 * (index % 9)],
                      child: Text("index: $index"),
                    )),
            gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
                maxCrossAxisExtent: 150,
                mainAxisSpacing: 10,
                crossAxisSpacing: 10,
                childAspectRatio: 1.4))
      ],
    );
  }
}

class CustomDelegate extends SliverPersistentHeaderDelegate {
  @override
  Widget build(
      BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      color: Colors.indigo,
      child: const FractionallySizedBox(
        heightFactor: 1,
        child: Center(
          child: Text('data'),
        ),
      ),
    );
  }

  @override
  double get maxExtent => 100;	//스크롤되었을 때 크기

  @override
  double get minExtent => 60;	//작아졌을 때 크기

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
    return false;
  }
}

설명.

CustomScrollView의 slivers: 속성에 있는 자식 위젯들은 아래와 같습니다.

  • SliverAppBar:
    • SliverAppBar는 확장 가능한 앱 바와 헤더를 정의하는 데 사용됩니다.
    • floating 속성을 true로 설정하여 스크롤을 내릴 때 앱 바가 같이 스크롤됩니다.
    • stretch 속성을 true로 설정하여 헤더를 당길 수 있도록 합니다.
    • pinned 속성을 true로 설정하여 헤더를 화면 상단에 고정합니다.
    • snap 속성을 true로 설정하여 스크롤할 때 앱 바가 확장된 상태로 나타나거나 사라집니다.
    • collapsedHeight는 앱 바의 크기를 설정하고, expandedHeight는 확장된 앱 바의 크기를 설정합니다.
    • flexibleSpace는 확장 가능한 공간에 헤더 내용을 정의합니다.
  • SliverToBoxAdapter:
    • SliverToBoxAdapter는 CustomScrollView 안에 일반적인 위젯을 추가할 때 사용됩니다.
    • 여기에서는 CircleAvatar 위젯을 사용하여 원형 이미지를 추가하고 있습니다.
  • SliverFixedExtentList:
    • SliverFixedExtentList는 CustomScrollView 안에 리스트를 만들 때 사용됩니다.
    • itemExtent 속성을 통해 각 항목의 높이를 설정합니다.
    • SliverChildBuilderDelegate를 사용하여 동적으로 아이템을 생성합니다.
  • SliverPersistentHeader:
    • SliverPersistentHeader는 헤더를 추가하고 고정시키는 데 사용됩니다.
    • CustomDelegate 클래스를 사용하여 커스텀 헤더 디자인을 정의하고 있습니다.
    • pinned 속성을 true로 설정하여 헤더를 화면 상단에 고정합니다.
  • SliverGrid:
    • SliverGrid는 CustomScrollView 안에 그리드를 만들 때 사용됩니다.
    • SliverChildBuilderDelegate를 사용하여 동적으로 그리드 항목을 생성합니다.
    • SliverGridDelegateWithMaxCrossAxisExtent를 사용하여 그리드 레이아웃을 설정합니다.

 

이것들은 CustomScrollView 내에서 다양한 레이아웃과 위젯을 조합하여 스크롤 가능한 화면을 만드는 방법을 보여주는 예제 코드입니다. 각 Sliver 위젯은 화면 스크롤 동작을 제어하고 다양한 레이아웃을 구성하는 데 사용됩니다.

 


빌드된 모습.

 

참고 및 출처: 노마드코더

반응형
Comments