[Flutter] 무한 스크롤 만들기(1) - Vertical

Tyger·2022년 12월 21일
1

Flutter

목록 보기
3/64
post-custom-banner

무한 스크롤 만들기 - Vertical

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

스크롤을 내리면서 아이템을 더 불러오는 무한 스크롤을 만들어보자

무한 스크롤을 개발하기 위해서는 스크롤의 현재 포지션 값을 알고 있어야 하고 불러온 아이템을 리스트에 넣어주는 기능을 구현해야 한다.

실제로는 API 통신으로 데이터를 가져와서 보여주고 하는데, 무한 스크롤 만들기에서는 이미지만 넣어주는 방식으로 기능을 만들었다.
데이터는 아래 사이트에서 무료 이미지를 id로 가져올 수 있게 제공해 주고 있어서 아래 사이트에 있는 이미지를 불러와서 무한 스크롤을 만들면 된다.

Data

Lorem Picusm

해당 사이트에 방문해 보면 여러 이미지를 가져올 수 있도록 무료로 제공해 주고 있는데, "https://picsum.photos/id/{index}/200/300" 이렇게 id 옆에 인덱스 부분에 숫자를 넣으면 다양한 종류의 이미지를 가져올 수 있다. 200은 width 값이고 300은 height 값이다.

Flutter

State Management - Provider

UI

UI 부분에는 단순히 네트워크 이미지를 보여주는 간단한 구조로 작성하였다. 하단에 보면 로딩 바를 구현하기 위해서 CircularProgressIndicator 위젯을 사용하여 현재 item이 마지막 item일 경우에만 로딩 바가 노출될 수 있도록 해줬다.

NotificationListener 위젯은 스크롤의 컨트롤러를 선언하지 않아도 스크롤 값을 받아올 수 있는 기능을 제공하고 있다.

NotificationListener<ScrollUpdateNotification>(
            onNotification: (ScrollUpdateNotification notification) {
              value.listner(notification);
              return false;
            },
            child: ListView.builder(
                itemCount: value.items.length,
                itemBuilder: (context, index) {
                  return Column(
                    children: [
                      Container(
                        padding: const EdgeInsets.symmetric(
                            horizontal: 20, vertical: 8),
                        child: ClipRRect(
                          borderRadius: BorderRadius.circular(12),
                          child: Image.network(
                            value.items[index],
                            fit: BoxFit.cover,
                            width: MediaQuery.of(context).size.width - 40,
                            height: MediaQuery.of(context).size.width - 40,
                          ),
                        ),
                      ),
                      if (value.isMore && value.currentIndex == index + 1) ...[
                        const Padding(
                          padding: EdgeInsets.symmetric(vertical: 40),
                          child: CircularProgressIndicator(
                            color: Colors.deepOrange,
                          ),
                        ),
                      ],
                    ],
                  );
                }),
          ),

Provider

무한 스크롤 로직을 만들기 위해 리스트 뷰에서 보여줄 items라는 List 타입의 변수와 현재 몇 번째 까지 호출을 했는지를 확인하기 위한 currentIndex 변수 그 다음 로딩 바를 구현하기 위해 불리언 값으로 isMore 변수를 생성해 주었다.

  List<String> items = [];
  int currentIndex = 0;
  bool isMore = false;

페이지에 접근시 최초 시작하는 함수를 만들었다.

해당 함수를 보면 반복문을 사용하여 items 변수에 1씩 증가한 url 값을 넣어주었다.

  Future<void> started() async {
    for (int i = 0; i < 20; i++) {
      items.add('https://picsum.photos/id/$i/200/200');
    }
    currentIndex = 20;
  }

스크롤에 의해서 아이템을 더 불러오기 위한 함수를 만들었다.

로딩 바를 확실히 보여주기 위해 3초간의 딜레이를 발생시킨 후 items에 20개의 url을 더 담아주는 로직이다.

함수 상단 부분에 isMore라는 함수를 활용하여 스크롤 포지션에 의해 아이템을 마구잡이로 불러오는 것을 방지하고 있다.

Future<void> _addItem() async {
    if (!isMore) {
      isMore = true;
      notifyListeners();
      Future.delayed(const Duration(milliseconds: 3000), () {
        for (int i = 0; i < 20; i++) {
          items.add('https://picsum.photos/id/${i + currentIndex}/200/200');
        }
        currentIndex = currentIndex + 20;
        isMore = false;
        notifyListeners();
      });
    }
  }

listener라는 함수에 ScrollUpdateNotification 값을 받아와 해당 뷰의 최대 스크롤 높이 값의 85프로가 도달하면 위에서 만들어준 _addItem() 함수를 호출시키는 로직이다.
listener 함수는 위에서 만들었던 NotificationListener 위젯 안에서 실행될 수 있도록 추가해주면 된다.

  void listner(ScrollUpdateNotification notification) {
    if (notification.metrics.maxScrollExtent * 0.85 <
        notification.metrics.pixels) {
      _addItem();
    }
  }

Git

https://github.com/boglbbogl/flutter_velog_sample/tree/main/lib/infinity_scroll

Result

마무리

Vertical 구조의 무한 스크롤 기능을 만들어 보았다. 물론 다양한 라이브러리들이 존재하고 대부분 라이브러리로 개발을 하지만 라이브러리를 사용하지 않고 직접 개발을 해보고 싶다면 이렇게 기능을 만들어 보면된다.

다음 시간에는 Horizontal 구조의 무한 스크롤에 대해서 작성하도록 하겠다.

profile
Flutter Developer
post-custom-banner

0개의 댓글