post-custom-banner

스크롤 인디케이터 직접 만들기 - Horizontal

스크롤 인디케이터 - Vertical
무한 스크롤 만들기 - Vertical
무한 스크롤 만들기 - Horizontal
무한 스크롤 만들기 - PageView

이번 글에서도 이전 글에 이어서 스크롤 바를 직접 개발하는 방법에 대해서 알아보도록 하겠다.

State Management - Provider

Flutter

UI

먼저 Horizontal Scroll이 가능하도록 위젯을 배치해준다.
NotificationListener() 위젯은 스크롤 포지션 값을 수신하는 기능을 가지는 위젯이다.

현재 UI에서는 ScrollController를 사용하지 않아도 되서 NotificationListener로 현재 스크롤 포지션 값을 수신하였다.

NotificationListener<ScrollUpdateNotification>(
                  onNotification: ((notification) {
                    value.scrollListener(
                        notification: notification,
                        widthSize: (MediaQuery.of(context).size.width / 3) -
                            (MediaQuery.of(context).size.width / 3) / 2);
                    return false;
                  }),
                  child: SingleChildScrollView(
                    scrollDirection: Axis.horizontal,
                    child: Row(
                      children: [
                        const SizedBox(width: 20),
                        ...List.generate(
                            14,
                            (index) => Padding(
                                  padding: const EdgeInsets.only(right: 10),
                                  child: Container(
                                    width:
                                        MediaQuery.of(context).size.width / 3,
                                    height: 160,
                                    decoration: BoxDecoration(
                                      borderRadius: BorderRadius.circular(8),
                                      color: Colors.accents[index],
                                    ),
                                  ),
                                )),
                      ],
                    ),
                  ),
                ),
                

위 위젯 아래에 Indicator로 사용할 위젯도 만들어줬다.

Container 안에 Stack 구조로 Position을 움직일 수 있는 구조로 만들어서 Indicator 역할을 할 수 있도록 하였다.

value.scrollPosition을 값을 Left position으로 사용하면 되고, 해당 변수를 변경해주는 방법은 아래에서 설명하도록 하겠다.

Padding(
                  padding: const EdgeInsets.only(top: 20, left: 20, right: 20),
                  child: Container(
                    width: MediaQuery.of(context).size.width / 3,
                    height: 5,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(100),
                      color: const Color.fromRGBO(91, 91, 91, 1),
                    ),
                    child: Stack(
                      children: [
                        Positioned(
                            left: value.scrollPosition,
                            child: Container(
                              height: 5,
                              width:
                                  (MediaQuery.of(context).size.width / 3) / 2,
                              decoration: BoxDecoration(
                                  borderRadius: BorderRadius.circular(100),
                                  color: Colors.white),
                            )),
                      ],
                    ),
                  ),
                ),

Provider

scrollPosition 변수를 선언해주고 아래 scrollListener() 함수를 만들어 UI 상단에 배치한 NotificationListener 위젯에서 수신하는 Scroll 값을 받아오면 된다.

ScrollUpdateNotification 값과, widthSize 값을 필수로 받아왔다.
ScrollUpdateNotification 객체에는 다양한 scroll과 관련된 기능이 담겨있다.

widthSize: (MediaQuery.of(context).size.width / 3) - (MediaQuery.of(context).size.width / 3) / 2)

widthSize는 위젯의 Indicator를 감싼 Container 가로 사이즈에서 Indicator 사이즈 만큼을 빼준 값이다.

double scrollPosition = 0.0;

  void scrollListener({
    required ScrollUpdateNotification notification,
    required double widthSize,
  }) {
    double _main = 0.0;

    _main = notification.metrics.maxScrollExtent / widthSize;
    scrollPosition = (notification.metrics.pixels / _main);
    notifyListeners();
  }

Git

해당 레포지토리에서 다운받아 실행 후 값을 변경해 보면서 해보면 이해가 더 빠를 것이다.

https://github.com/boglbbogl/flutter_velog_sample/tree/main/lib/scroll/horizontal_indicator

Result

profile
Flutter Developer
post-custom-banner

0개의 댓글