自分用メモ flutterのPageViewをほかのイベントからページ切り替えする方法


PageViewをプログラム側からページ切り替えしようと思ったら詰まった

やりたかったこと

ボタンとドロップダウンリストを使ってページ切り替え

説明に「PageControllerのinitialPage:で最初に表示するページを設定する」みたいなことが書いてあったので、なるほどPageControllerを再作成して切り替えたいページを指定するんだなと思って↓を書いた


//MyPageWidgetは省略

class MyPageState extends State<MyPageWidget>{
   var _currentPage = 0;
   @Override 
   Widget build(BuildContext context) {
      final controller = PageController(initialPage: _currentPage);
      return Column(
      children: <Widget>[
        Row( //ボタン用の行widget
          children: <Widget>[
            IconButton( //前ページボタン
              icon: Icon(Icons.navigate_before),
              onPressed: _currentPage > 0 ? () { //クリックイベント処理
                setState(){ _currentPage--;};
              } : null,
            ),
            Expanded( //ドロップダウンリストを余白いっぱいに引き伸ばす
              child: DropdownButton( //ドロップダウンリスト
                isExpanded: true,
                value: _current,
                items: List.generate(
                    12,
                    (index) => DropdownMenuItem(
                          value: index,
                          child: Text(
                            index.toString(),
                            textAlign: TextAlign.center,
                            textScaleFactor: 1.5,
                          ),
                        )),
                onChanged: (value) { //アイテム選択イベント処理
                  if (value is int) setState(){ _currentPage = value; };
                },
              ),
            ),
            IconButton( //次ページボタン
              icon: Icon(Icons.navigate_next),
              onPressed: _current < 11 ? (){ setState(){ _currentPage++ ;} : null,
            )
          ],
        ),
        Expanded( //PageViewはサイズが可変なので、Column Widgetに入れるときはこれに入れる
          child: PageView.builder(
              itemCount: 12,
              controller: _mController,
              onPageChanged: (index){ //ページ変更イベント処理
                setState(() {
                  _current = index;
                });
              },
              itemBuilder: (context, index){
                 return Center( child: Text((index + 1).toString() + "ページ",textScaleFactor: 3;
              }),
        )
      ],
    )

※動きません

flutterのPageViewリファレンスページをよく見ると

The PageController can also be used to control the PageController.initialPage, which determines which page is shown when the PageView is first constructed,

ページビューが最初に作成された時に表示されるページを決定する(雑訳)

つまりこれ、最初の一回だけページを指定するのであって、ページを移動するためには使えない、ということか!?

PageControllerのリファレンスを見ると……

METHODS

animateToPage
attach
createScrollPosition
jumpToPage
nextPage
previousPage
addListener

↑はい、この辺を使うんですね分かります。


//MyPageWidgetは省略

class MyPageState extends State<MyPageWidget>{
   var _currentPage = 0;
   var duration = Duration(milisecond: 200); //アニメーションする時間
   var curve = Curves.fastInSlowOut; //アニメーションの動き
   @Override 
   Widget build(BuildContext context) {
      final controller = PageController();

      //色々省略

      onPressed: _current > 0 ? (){ //前ページボタンイベント処理
           controller.previousPage(duration: duration,curve: curve);
         },
      //色々省略
                onChanged: (value) { //ドロップダウンリストアイテム選択イベント処理
                  if (value is int) {
                     controller.jumpToPage(value);
                  };
                },
       //色々省略
       onPressed: _current > 0 ? (){ //前ページボタンイベント処理
           controller.nextPage(duration: duration,curve: curve);
         },
   //色々省略
}

*これで動いた
*durationやcurveを変えるとアニメーションも変わる

気付かなかった理由

flutterのUIフレームワークになれすぎた。
何かを変更するときは値を変えてsetState()すれば終わりだと思ってた。
っていうかAnimatedContainerはsetState()で値変えたら自動でアニメーションするからさあ……(見苦しい言い訳)

androidStudioではずっとそうやって使ってきたのに完全に忘れちゃってたな。

おまけ

これらのメソッドはFutureクラスを返すので、


   controller.nextPage( duration: duration, curve:curve)
      .whenComplete((){
          //なにかの処理
       });

こうすれば、ページ切り替えが終わったあとに何らかの処理をする事ができる。