Flutter에 smooth_page_indicator라는 라이브러리가 있어서 사용해보았습니다.
https://pub.dev/packages/smooth_page_indicator
먼저 여기서 install 하고
간단하게 코드를 살펴보면
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
class IndicatorPage extends StatefulWidget {
const IndicatorPage({Key? key}) : super(key: key);
@override
State<IndicatorPage> createState() => _IndicatorPageState();
}
class _IndicatorPageState extends State<IndicatorPage> {
final controller = PageController(
viewportFraction: 0.8,
keepPage: false,
initialPage: 0,
);
final pages = List.generate(
6,
(index) => Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
color: Colors.grey.shade300,
),
margin: EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Container(
height: 280,
child: Center(
child: Text(
"Page $index",
style: TextStyle(color: Colors.indigo),
)),
),
));
void autoPagination() async {
await Timer.periodic(Duration(seconds: 3), (timer) {
controller.nextPage(
duration: Duration(milliseconds: 300),
curve: Curves.easeIn,
);
});
}
@override
void initState() {
autoPagination();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Smooth Page Indicator',
),
elevation: 0,
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
height: 10,
),
SizedBox(
height: 240,
child: PageView.builder(
controller: controller,
// itemCount: pages.length,
itemBuilder: (_, index) {
return pages[index % pages.length];
},
),
),
SizedBox(
height: 10,
),
Center(
child: SmoothPageIndicator(
controller: controller,
count: pages.length,
effect: const WormEffect(
dotHeight: 16,
dotWidth: 16,
type: WormType.thinUnderground,
),
),
),
SizedBox(
height: 10,
),
Center(
child: SmoothPageIndicator(
controller: controller,
count: pages.length,
effect: JumpingDotEffect(
dotHeight: 16,
dotWidth: 16,
jumpScale: .7,
verticalOffset: 15,
),
),
),
SizedBox(
height: 20,
),
Center(
child: SmoothPageIndicator(
controller: controller,
count: pages.length,
effect: ScrollingDotsEffect(
activeStrokeWidth: 2.6,
activeDotScale: 1.3,
maxVisibleDots: 5,
radius: 8,
spacing: 10,
dotHeight: 16,
dotWidth: 16,
),
),
),
SizedBox(
height: 20,
),
Center(
child: SmoothPageIndicator(
controller: controller,
count: pages.length,
effect: SwapEffect(
radius: 8,
spacing: 10,
dotHeight: 16,
dotWidth: 16,
),
),
),
SizedBox(
height: 20,
),
Center(
child: Container(
child: SmoothPageIndicator(
controller: controller,
count: pages.length,
effect: CustomizableEffect(
activeDotDecoration: DotDecoration(
width: 20,
height: 12,
rotationAngle: 180,
verticalOffset: -10,
borderRadius: BorderRadius.circular(24),
),
dotDecoration: DotDecoration(
width: 12,
height: 12,
color: Colors.grey,
borderRadius: BorderRadius.circular(16),
verticalOffset: 0,
),
spacing: 12.0,
activeColorOverride: (i) => colors[i],
inActiveColorOverride: (i) => colors[i],
),
),
),
),
SizedBox()
],
),
);
}
}
final colors = const [
Colors.red,
Colors.green,
Colors.greenAccent,
Colors.amberAccent,
Colors.blue,
Colors.amber,
];
이런 저런 기능들을 사용해보았는데 pub dev에 설명이나 예시가 잘 써있어서 쓰는데에 불편한 점은 없었습니다.
아쉬운 점이 있다면 자동페이지네이션 기능이 따로 없다는것 정도인데 이거는 pagecontroller에서 지원하지않는 기능이니 직접 구현해서 넣어 보았습니다.
저 코드를 그대로 실행하면 에러를 뱉는데 이유는 제가 pageview에 length를 주지 않고 무한 스크롤로 구현을 하였는데 SwapEffect는 infinite scroll을 지원하지 않기 때문입니다.
원래 저는 저 UI를 구현할 때 carousel_slider로 구현하였었는데 이제는 좀 더 범용적으로 사용할 수 있는 pageview를 사용해야겠습니다.