今回作るもの
Webでは過去に無限にスクロールできるカルーセルスライダーを実装したことがあったのですが、Flutterでどうやるんだろう?と思い調べてみました。
(いらすとやから、最近流行りの「ヤツ」を使ってみました)
トップ画面 | ボトムシート | 動画 |
---|---|---|
![]() |
![]() |
![]() |
使用したパッケージ
今回は、このようなカルーセルが簡単にできるcarousel_sliderを採用しました。
パッケージ選定の条件的には問題なさそうです

実際のウィジェット(サンプル)
カルーセルに出したいリスト
final List<String> images = [
'assets/kodai_sacabambaspis.png',
];
カルーセルの要素
class _CarouselCard extends StatelessWidget {
const _CarouselCard({
required this.image,
});
final String image;
@override
Widget build(BuildContext context) {
return Container(
height: 180,
width: 120,
decoration: BoxDecoration(
color: Colors.black54,
borderRadius: BorderRadius.circular(20),
),
child: SizedBox(
child: Image(
image: AssetImage(image),
fit: BoxFit.fitWidth,
),
),
);
}
}
今回のメインどころ
今回は、CarouserlSlider.builder
を用いてカルーセルを設定しています。
CarouselSlider
のitemBuilder
は3つの引数を持ちます。
itemBuilder:
(BuildContext context, int itemIndex, int pageViewIndex) {
return _CarouselCard(image: images[itemIndex]);
},
- 第一引数: お馴染みのBuildContext
- 第二引数: スライダーの要素のindexが取れます(
images
)
たとえば、配列要素が10件あった場合は0~9の値が取れます。 - 第三引数: 擬似的なindex(詳細は後ほど説明します)
スライドできるカルーセル
class _CarouselSlider extends StatelessWidget {
const _CarouselSlider();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 24),
child: SizedBox(
height: 180,
child: CarouselSlider.builder(
itemCount: images.length,
itemBuilder:
(BuildContext context, int itemIndex, int pageViewIndex) {
return _CarouselCard(image: images[itemIndex]);
},
options: CarouselOptions(
height: 180,
viewportFraction: 0.35, // カルーセルの横幅を管理します
),
),
),
);
}
}
気休めにボトムシートエリアです
class _BottomSheetWidget extends StatelessWidget {
const _BottomSheetWidget();
@override
Widget build(BuildContext context) {
return Container(
height: 500,
width: double.maxFinite,
// 上だけ丸める
decoration: const BoxDecoration(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
color: Color.fromARGB(42, 255, 255, 255),
),
child: const Padding(
padding: EdgeInsets.symmetric(vertical: 20),
child: Column(
children: [
_CarouselSlider(),
],
),
),
);
}
}
注意点
実は、このcarousel_sliderは無限ではありません。
itemBuilder
の先ほど3つの引数の話をしましたが、その中のpageViewIndex
はどうなっているのか調べてみました。
パッケージの該当箇所を見てみます。
carousel_slider-4.2.1/lib/carousel_state.dart
class CarouselState {
/// The [CarouselOptions] to create this state
CarouselOptions options;
/// [pageController] is created using the properties passed to the constructor
/// and can be used to control the [PageView] it is passed to.
PageController? pageController;
/// The actual index of the [PageView].
///
/// This value can be ignored unless you know the carousel will be scrolled
/// backwards more then 10000 pages.
/// Defaults to 10000 to simulate infinite backwards scrolling.
int realPage = 10000;
/// The initial index of the [PageView] on [CarouselSlider] init.
///
int initialPage = 0;
/// The widgets count that should be shown at carousel
int? itemCount;
/// Will be called when using pageController to go to next page or
/// previous page. It will clear the autoPlay timer.
/// Internal use only
Function onResetTimer;
/// Will be called when using pageController to go to next page or
/// previous page. It will restart the autoPlay timer.
/// Internal use only
Function onResumeTimer;
/// The callback to set the Reason Carousel changed
Function(CarouselPageChangedReason) changeMode;
CarouselState(
this.options, this.onResetTimer, this.onResumeTimer, this.changeMode);
}
以下にある通り、上限は10000要素だということがわかりました。
carousel_slider-4.2.1/lib/carousel_state.dart
/// The actual index of the [PageView].
///
/// This value can be ignored unless you know the carousel will be scrolled
/// backwards more then 10000 pages.
/// Defaults to 10000 to simulate infinite backwards scrolling.
int realPage = 10000;
実際に10000個分もスクロールするユーザーは稀かと思いますが、実は無限ではないという点には気をつけておきましょう。