본문 바로가기
flutter

[플러터] Flutter / 페이징 기능 제작 (Pagination, Paging) (페이지 넘기는 기능)

by ch5c 2025. 1. 7.
반응형

데이터를 불러올 때 페이지 형식으로 가져와지는 데이터가 있다. 나로 예를 들자면 TMDB에서 영화 데이터를 쓰려고 하는데 url을 이런 식으로 주고 있었다.

https://api.themoviedb.org/3/movie/now_playing?language=en-US&page=1"

당연하게도 이 데이터를 가져오면 1페이지의 데이터밖에 못 뽑기 때문에 나는 페이지네이션 기능을 제작하기로 했다.

(애초에 넣어야 하긴 했다)

 

먼저 사용할 변수 선언.

int currentPage = 1;
int totalPages = 1;

 

그런 다음 현재 내 코드에서 데이터 처리를 하고 있는 함수 안에 page 값을 추가하였다.

Future<void> getMovieList({int page = 1}) async {
await Client().get(Uri.parse('$base_url/movie/now_playing?page=$page'),
currentPage = json['page'];
totalPages = json['total_pages'];

(다루지 않을 건 다 뺏다)

 

그런 다음 중요 메서드 작성

void changePage(int newPage) async {
  if (newPage == currentPage) return;
  await getMovieList(page: newPage);
  currentPage = newPage;
  notifyListeners();
}

 

페이지 번호를 변경하고 새로운 페이지에 해당하는 영화 목록을 가져오게 만들었다.

List<int> getDisplayedPages() {
  const maxPagesToShow = 5;

  int startPage = (currentPage - 2).clamp(1, totalPages);
  int endPage = (currentPage + 2).clamp(1, totalPages);

  if (totalPages <= maxPagesToShow) {
    startPage = 1;
    endPage = totalPages;
  } else if (endPage - startPage + 1 < maxPagesToShow) {
    if (startPage == 1) {
      endPage = startPage + maxPagesToShow - 1;
    } else if (endPage == totalPages) {
      startPage = endPage - maxPagesToShow + 1;
    }
  }
  return List.generate(
    endPage - startPage + 1,
    (index) => startPage + index,
  );
}

 

화면에 표시되는 동작을 처리하게 만들었다.

그리고 이제 기능을 만들었으니 화면도 만들어야 할 것이다. 페이지 로직은 따로 분리해서 위젯으로 만들었다.

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

  @override
  State<MoviePage> createState() => _MoviePageState();
}

class _MoviePageState extends State<MoviePage> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: backgroundColor,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          IconButton(
            icon: const Icon(
              CupertinoIcons.back,
              color: Colors.white,
            ),
            onPressed: movieProvider.currentPage > 1
                ? () => movieProvider.changePage(movieProvider.currentPage - 1)
                : () => movieProvider.changePage(movieProvider.totalPages),
          ),
          ...movieProvider.getDisplayedPages().map(
                (page) {
              return GestureDetector(
                onTap: () => movieProvider.changePage(page),
                child: Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 5),
                  child: Text(
                    '$page',
                    style: TextStyle(
                      color: movieProvider.currentPage == page
                          ? Colors.white
                          : Colors.grey,
                      fontSize: 18,
                    ),
                  ),
                ),
              );
            },
          ),
          IconButton(
            icon: const Icon(
              CupertinoIcons.forward,
              color: Colors.white,
            ),
            onPressed: movieProvider.currentPage < movieProvider.totalPages
                ? () => movieProvider.changePage(movieProvider.currentPage + 1)
                : () => movieProvider.changePage(1), // 마지막 페이지에서 첫 페이지로 이동
          ),
        ],
      ),
    );
  }
}

 

코드 알잘딱으로 잘 필터링해서 보길 바란다.

이제 이렇게 제작된 결과물을 봐보자.

잘 작동이 되는 모습이다. (중간중간 로딩이 느린 건 그냥 내 인터넷이 느린 거다.)

 

이렇게 오늘 페이징 기능을 만들어 보았다. 도움이 되었길 바라며 포스팅 마치겠다.

반응형

 

반응형