【Flutter】carousel_sliderで画像をスライドショーにする方法

carousel_sliderとは

flutterのパッケージの一種で、画像やウィジェットをスライドショーとして動かすことができます。

画像を複数枚並べたい時などに使われます。

使用環境

VScode バージョン: 1.84.2

Flutter バージョン: 3.76.0

carousel_slider: ^4.2.1

実装

動作画面と実装コードです。

各ウィジェットのレイアウトが分かるように色分けをしました。

slider[な]slider[ナ]
slider[こ]slider[し]
画像をスワイプすると次のスライドが表示される

以下実装コードです。(抜粋)

final carouselSliderNumberProvider = StateProvider<int>((ref) => 0);

class ImageSlider extends ConsumerWidget {
  ImageSlider({Key? key}) : super(key: key);

  final imageList = [
    '「な」の画像のURL',
    '「ナ」の画像のURL',
    '「こ」の画像のURL',
    '「し」の画像のURL'
  ];

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    int carouselSliderNumber = ref.watch(carouselSliderNumberProvider);

-----
省略
-----
            child: CarouselSlider.builder(
              options: CarouselOptions(
                  height: 300,
                  initialPage: 0,
                  viewportFraction: 1,
                  enlargeCenterPage: true,
                  onPageChanged: (index, reason) {
                    ref.watch(carouselSliderNumberProvider.notifier).state 
                       = carouselSliderNumber = index;
                  }),
              itemCount: imageList.length,
              itemBuilder: (context, index, realIndex) {
                final path = imageList[index];
                return buildImage(path, index);
              },
            ),
          ),
          const SizedBox(height: 20),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: imageList.map((url) {
              int index = imageList.indexOf(url);
              return Container(
                width: 15,
                height: 15,
                margin:const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: carouselSliderNumber == index
                      ? const Color.fromRGBO(115, 137, 187, 1)
                      : const Color.fromRGBO(115, 137, 187, 0.4),
                ),
              );
            }).toList(),
          ),
        ],
      )),
    );
  }

-----
省略

解説

final carouselSliderNumberProvider = StateProvider<int>((ref) => 0);

int carouselSliderNumber = ref.watch(carouselSliderNumberProvider);

現在のスライドショーの番号をRiverpodのStateProviderで監視します。

配列のインデックスは0から始まるので初期値は0にします。

監視している数字をcarouselSliderNumberと定義します。

  final imageList = [
    '「な」の画像のURL',
    '「ナ」の画像のURL',
    '「こ」の画像のURL',
    '「し」の画像のURL'
  ];

表示させたい画像のURLをリストにまとめておきます。

            child: CarouselSlider.builder(
              options: CarouselOptions(
                  height: 300,
                  initialPage: 0,
                  viewportFraction: 1,
                  enlargeCenterPage: true,
                  onPageChanged: (index, reason) {
                    ref.watch(carouselSliderNumberProvider.notifier).state 
                       = carouselSliderNumber = index;
 

CarouselSlider.builderでスライダーを描画

CarouselOptionsでスライダーの動きなどをカスタムできます。

onPageChanged: スライドが切り替わった時の動作

notifireで現在の配列番号の更新を依頼、state(状態)を切り替わったスライド番号に変更する。

itemCount: imageList.length,
              itemBuilder: (context, index, realIndex) {
                final path = imageList[index];
                return buildImage(path, index);

itemBuilder:スライダーに表示したい画像を描画

itemCount:表示したいアイテム数を指定

imageList.length つまりImageListの配列全て表示させる(今回は4つ)

return buildImageで画像データが入ったウィジェットを呼び出す(内容はソースコード参照)

return Container(
                width: 15,
                height: 15,
                margin:const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: carouselSliderNumber == index
                      ? const Color.fromRGBO(115, 137, 187, 1)
                      : const Color.fromRGBO(115, 137, 187, 0.4),
                ),
              );

ここでスライダー下の●を作成

三項演算子を使用し、スライダーの動きと連動して●の色の切り替えを行なっている

条件式 ( carouselSliderNumber が index(0~3の配列番号)と等しい )

? ( trueなら濃い青 ) : ( falseなら薄い青 ) になる

つまり、今表示されているスライドの●が濃い青色になり、それ以外の●は薄い青色になる

ソースコード

全体のソースコードになります。

final carouselSliderNumberProvider = StateProvider<int>((ref) => 0);

class ImageSlider extends ConsumerWidget {
  ImageSlider({Key? key}) : super(key: key);

     final imageList = [
    '「な」の画像のURL',
    '「ナ」の画像のURL',
    '「こ」の画像のURL',
    '「し」の画像のURL'
  ];

  @override
  Widget build(BuildContext context, WidgetRef ref) {

    int carouselSliderNumber = ref.watch(carouselSliderNumberProvider);

    return Scaffold(
      backgroundColor: const Color.fromRGBO(254, 243, 239, 1),
      body: Center(
          child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Text('カルーセルスライダーで[なナこし]と表示'),
          const SizedBox(height: 20),
          Container(
            color: const Color.fromRGBO(214, 228, 231, 1),
            child: CarouselSlider.builder(
              options: CarouselOptions(
                  height: 300,
                  initialPage: 0,
                  viewportFraction: 1,
                  enlargeCenterPage: true,
                  onPageChanged: (index, reason) {
                    ref.watch(carouselSliderNumberProvider.notifier).state 
                       = carouselSliderNumber = index;
                  }),
              itemCount: imageList.length,
              itemBuilder: (context, index, realIndex) {
                final path = imageList[index];
                return buildImage(path, index);
              },
            ),
          ),
          const SizedBox(height: 20),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: imageList.map((url) {
              int index = imageList.indexOf(url);
              return Container(
                width: 15,
                height: 15,
                margin:const EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  color: carouselSliderNumber == index
                      ? const Color.fromRGBO(115, 137, 187, 1)
                      : const Color.fromRGBO(115, 137, 187, 0.4),
                ),
              );
            }).toList(),
          ),
        ],
      )),
    );
  }

//表示したい画像のウィジェット
  Widget buildImage(path, index) {
    return Container(
      color: const Color.fromRGBO(166, 190, 214, 1),
      child: Image.network(
        path,
        fit: BoxFit.cover,
      ),
    );
  }
}

いかがだったでしょうか?

ご意見、ご感想ありましたらお気軽にコメントしてください。

carousel_sliderを使うとスライドショーが手軽に実装でき、ECアプリなどの商品紹介に使えそうですよね。

【参考文献】

コメント

タイトルとURLをコピーしました