4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

watnowAdvent Calendar 2022

Day 11

Flutter carousel_sliderでアクティブなcontrollerを表示したい

Posted at

業務でFlutterを用いる際、簡単にカルーセルを使用するためにcarousel_sliderというパッケージを導入しました
carousel_sliderの機能には、カルーセルそのものを左右にスワイプして動かすほか、独立した他のwidgetにCarouselControllerオブジェクトを操作させて動かすものがあります

pub.devに記載のexampleでは以下のように使用されています

final CarouselController _controller = CarouselController();

carouselController: _controller,

操作widget

...Iterable<int>.generate(imgList.length).map(
    (int pageIndex) => Flexible(
        child: ElevatedButton(
            onPressed: () => _controller.animateToPage(pageIndex),
            child: Text("$pageIndex"),
        ),
    ),
),

このままで操作は可能なのですが、選択されている(アクティブな)操作widgetを明示したい場合があります

その際に以下のように、外部のstateなどで選択されているインデックスを保存しそれが選択されたインデックスと同じか判定することで実装するとします

int selectedIndex = 0;
void onPressed(int pageIndex) {
    setState(() {
        selectedIndex = pageIndex;
    });
    this._controller.animateToPage(pageIndex);
}

//~~~略~~~

...Iterable<int>.generate(widget.images!.length).map(
    (int pageIndex) => Flexible(
        child: TextButton(
            onPressed: () {
                onPressed(pageIndex);
            },
            child: Container(
                decoration: pageIndex == selectedIndex
                    ? BoxDecoration(border: Border.all(width: 2))
                    : null,
                child: Image.network(
                    widget.images![pageIndex],
                ),
            ),
        ),
    ),
),
//~~~

この実装で、controllerを用いてカルーセルを動かした際に選択されたwidgetがアクティブであると表示できました

しかしこのままではcontrollerではなくカルーセル部分をスワイプしてカルーセルを切り替えるとselectedIndexが切り替わらずアクティブの表示ができない問題が発生します
そこで、カルーセルからの操作を検知してアクティブなインデックスを切り替えるように追記します

CarouselOptionsonPageChangedを記述することでこのような変更を受け取って実行される関数を指定できます

CarouselSlider(
    options: CarouselOptions(
        onPageChanged: (index, reason) => {
            onPressed(index)
        },

このように書くとカルーセルが動いた際に動いた直後のインデックスを引数として更新する関数を実行します
そのため、実際にはこのコードだと
「コントローラーから移動先を指定する」

「指定通りにカルーセルが動き出す」

「カルーセルが動き出したためonPageChangedが発火」

「ここでインデックスに渡されるのは動き出した先のカルーセルなので指定に関係なくすぐ横のカルーセルにpageindexが更新される」

といった流れで操作すると強制的に次のページになってしまう減少が発生します
これを避けるため、カルーセルが更新されたときの条件として、コントローラー経由の際には自動で更新を行わないよう追記します

onPageChangedの第二引数でreasonというものがあり、具体的には

enum CarouselPageChangedReason { timed, manual, controller }

として3種類の値が定義されるCarouselPageChangedReasonオブジェクトを受け取れます

これを用いて次のように記述すると以上の問題が解決されます

onPageChanged: (index, reason) => {
    if (reason == CarouselPageChangedReason.timed ||
        reason == CarouselPageChangedReason.manual)
            {onPressed(index)}
},
4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?