15
8

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 5 years have passed since last update.

FlutterでPageViewにPageIndicatorを実装してみた

Posted at

よくあるPageViewを実装してみたかった。

↓こういうやつ
スクリーンショット 2019-11-06 13.44.28.png

一番最後にはIndicatorをボタンに変化させてよくある説明ページみたいなのを実装しています。

今回使用したライブラリーは以下の二つです。

メインのIndicator↓
https://pub.dev/packages/flutter_page_indicator

Indicatorのアニメーション↓
https://pub.dev/packages/transformer_page_view

パッケージの準備

パッケージのインストール

pubspec.yaml
dependencies:
  flutter_page_indicator: ^0.0.3
  transformer_page_view: ^0.1.6

上記を記載後
packages getを実行

パッケージのインポート

main.dart
import 'package:flutter_page_indicator/flutter_page_indicator.dart';
import "package:transformer_page_view/transformer_page_view.dart";

実装

全体コード

main.dart
import 'package:flutter/material.dart';

import 'package:flutter_page_indicator/flutter_page_indicator.dart';

import "package:transformer_page_view/transformer_page_view.dart";


class MyAppView extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MyHomePage();
  }

}

class MyHomePage extends StatefulWidget {

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double size = 20.0;
  double activeSize = 30.0;

  PageController controller;

  bool loop = false;

  bool _visible1 = true;
  var page_count = 1;

  void pageNumberChange(page) {
    setState(() {
      page_count = page + 1;
    });
  }

  @override
  void initState() {
    controller = new PageController();
    super.initState();
  }

  @override
  void didUpdateWidget(MyHomePage oldWidget) {

    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    var children = <Widget>[
      new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明1アプリの説明1",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                      Navigator.pushNamed(context, '/test');
                    },
                    child: Text("1枚目"),
                  ),
                ),
                Text(
                  "アプリの説明1アプリの説明1アプリの説明1アプリの説明1アプリの説明1",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
      new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明2アプリの説明2",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                      Navigator.pushNamed(context, '/test');
                    },
                    child: Text("2枚目"),
                  ),
                ),
                Text(
                  "アプリの説明2アプリの説明2アプリの説明2アプリの説明2アプリの説明2",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
      new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明3アプリの説明3",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                    },
                    child: Text("3枚目"),
                  ),
                ),
                Text(
                  "アプリの説明3アプリの説明3アプリの説明3アプリの説明3アプリの説明3",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明4アプリの説明4",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                    },
                    child: Text("4枚目"),
                  ),
                ),
                Text(
                  "アプリの説明4アプリの説明4アプリの説明4アプリの説明4アプリの説明4",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    ];

    //Widgetを生成

    return new Scaffold(
        appBar: new AppBar(
          title: new Text("アプリ説明ページ"),
        ),
        body: new Column(
          children: <Widget>[
            new Expanded(
                child: new Stack(
                  children: <Widget>[
                    loop ? new TransformerPageView.children(
                      children: children,
                      pageController: controller,
                    ):
                    new PageView(
                      onPageChanged: (page_count){
                        pageNumberChange(page_count);
                        if(page_count + 1 == children.length){
                          _visible1 = false;
                        }else{
                          _visible1 = true;
                        }
                      },
                      controller: controller,
                      children:children ,
                    ),
                    new Align(
                      alignment: Alignment.bottomCenter,
                      child: new Padding(
                        padding: new EdgeInsets.only(bottom: 20.0),
                        child: new Stack(
                          children: <Widget>[
                            Align(
                              alignment: Alignment.bottomCenter,
                              child: new Padding(
                                  padding: new EdgeInsets.only(bottom: 20.0),
                                  child: AnimatedOpacity(
                                    opacity: _visible1 ? 1.0 : 0.0,
                                    duration: Duration(milliseconds: 500),
                                    child: PageIndicator(
                                      layout: PageIndicatorLayout.NONE,
                                      size: size,
                                      activeSize:activeSize,
                                      controller: controller,
                                      space: 20,
                                      count: 4,
                                      color: Colors.black,
                                      activeColor: Colors.red,
                                    ),
                                  ),
                              )
                            ),
                            Align(
                              alignment: Alignment.bottomCenter,
                              child: new Padding(
                                  padding: new EdgeInsets.only(bottom:  20.0),
                                  child: AnimatedOpacity(
                                    opacity: _visible1 ? 0.0 : 1.0,
                                    duration: Duration(milliseconds: 500),
                                    child:SizedBox(
                                      width: 300,
                                      height: 50,
                                      child: RaisedButton(
                                        color: Colors.blue,
                                        onPressed: () {
                                          Navigator.pushNamed(
                                              context,
                                              '/hello'
                                          );
                                        },
                                        shape: RoundedRectangleBorder(
                                            borderRadius: BorderRadius.all(
                                                Radius.circular(5.0))
                                        ),
                                        child: Text(
                                          "はじめる",
                                          style: TextStyle(
                                              fontSize: 20.0,
                                              color: Colors.white
                                          ),
                                        ),
                                      ),
                                    ),
                                  ),
                              ),
                            )
                          ],
                        )
                      ),
                    )
                  ],
                )
            )
          ],
        )
    );
  }
}

部分別の解説

①説明ページのWidgetを配列にそ追加

childrenに4つの説明ページを入れています。
(ここほんとはメソッドでループ回したい…)

main.dart
//省略
@override
  Widget build(BuildContext context) {
    var children = <Widget>[
      new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明1アプリの説明1",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                      Navigator.pushNamed(context, '/test');
                    },
                    child: Text("1枚目"),
                  ),
                ),
                Text(
                  "アプリの説明1アプリの説明1アプリの説明1アプリの説明1アプリの説明1",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
      new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明2アプリの説明2",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                      Navigator.pushNamed(context, '/test');
                    },
                    child: Text("2枚目"),
                  ),
                ),
                Text(
                  "アプリの説明2アプリの説明2アプリの説明2アプリの説明2アプリの説明2",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
      new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明3アプリの説明3",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                    },
                    child: Text("3枚目"),
                  ),
                ),
                Text(
                  "アプリの説明3アプリの説明3アプリの説明3アプリの説明3アプリの説明3",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),new Column(
        children: <Widget>[
          Container(
            height: 150,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  "アプリの説明4アプリの説明4",
                  style: TextStyle(
                      fontSize: 24.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
          Container(
            width: 300,
            height: 300,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                SizedBox(
                  width: 300,
                  height: 200,
                  child: FlatButton(
                    color: Colors.black54,
                    onPressed: () {
                    },
                    child: Text("4枚目"),
                  ),
                ),
                Text(
                  "アプリの説明4アプリの説明4アプリの説明4アプリの説明4アプリの説明4",
                  style: TextStyle(
                      fontSize: 14.0,
                      color: Colors.black54
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    ];

②説明ページの配置と、下部にIndicator、ボタンの配置

PageIndicatorFlatButtonStack構造にして、
PageViewonPageChangedメソッドで最終ページにスワイプ時
アニメーションでボタンに切り替えるようにしています。

main.dart
return new Scaffold(
        appBar: new AppBar(
          title: new Text("アプリ説明ページ"),
        ),
        body: new Column(
          children: <Widget>[
            new Expanded(
                child: new Stack(
                  children: <Widget>[
                    loop ? new TransformerPageView.children(
                      children: children,
                      pageController: controller,
                    ):
                    new PageView(
                      onPageChanged: (page_count){
                        pageNumberChange(page_count);
                        if(page_count + 1 == children.length){
                          _visible1 = false;
                        }else{
                          _visible1 = true;
                        }
                      },
                      controller: controller,
                      children:children ,
                    ),
                    new Align(
                      alignment: Alignment.bottomCenter,
                      child: new Padding(
                        padding: new EdgeInsets.only(bottom: 20.0),
                        child: new Stack(
                          children: <Widget>[
                            Align(
                              alignment: Alignment.bottomCenter,
                              child: new Padding(
                                  padding: new EdgeInsets.only(bottom: 20.0),
                                  child: AnimatedOpacity(
                                    opacity: _visible1 ? 1.0 : 0.0,
                                    duration: Duration(milliseconds: 500),
                                    child: PageIndicator(
                                      layout: PageIndicatorLayout.NONE,
                                      size: size,
                                      activeSize:activeSize,
                                      controller: controller,
                                      space: 20,
                                      count: 4,
                                      color: Colors.black,
                                      activeColor: Colors.red,
                                    ),
                                  ),
                              )
                            ),
                            Align(
                              alignment: Alignment.bottomCenter,
                              child: new Padding(
                                  padding: new EdgeInsets.only(bottom:  20.0),
                                  child: AnimatedOpacity(
                                    opacity: _visible1 ? 0.0 : 1.0,
                                    duration: Duration(milliseconds: 500),
                                    child:SizedBox(
                                      width: 300,
                                      height: 50,
                                      child: RaisedButton(
                                        color: Colors.blue,
                                        onPressed: () {
                                          Navigator.pushNamed(
                                              context,
                                              '/hello'
                                          );
                                        },
                                        shape: RoundedRectangleBorder(
                                            borderRadius: BorderRadius.all(
                                                Radius.circular(5.0))
                                        ),
                                        child: Text(
                                          "はじめる",
                                          style: TextStyle(
                                              fontSize: 20.0,
                                              color: Colors.white
                                          ),
                                        ),
                                      ),
                                    ),
                                  ),
                              ),
                            )
                          ],
                        )
                      ),
                    )
                  ],
                )
            )
          ],
        )
    );

完成したもの

simulator-compressor.gif

ボタンの遷移のところは、
PageIndicatorlayoutを変更すればいろんなアニメーションになります。
詳しくはパッケージのドキュメントを参照してください!

最後に

ネストがすごい深くなってしまったので反省しています。
childrenのところとか他の部分もいろいろ直せる部分多いと思うので、
ぜひご指摘ください。

Flutter楽しいです。

15
8
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
15
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?