반응형
데이터를 불러올 때 페이지 형식으로 가져와지는 데이터가 있다. 나로 예를 들자면 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), // 마지막 페이지에서 첫 페이지로 이동
),
],
),
);
}
}
코드 알잘딱으로 잘 필터링해서 보길 바란다.
이제 이렇게 제작된 결과물을 봐보자.
잘 작동이 되는 모습이다. (중간중간 로딩이 느린 건 그냥 내 인터넷이 느린 거다.)
이렇게 오늘 페이징 기능을 만들어 보았다. 도움이 되었길 바라며 포스팅 마치겠다.
반응형
반응형