Flutter notes

Flutterに関するメモ書き

カードをめくるエフェクト(Webでも動くやつ)

ふと、カードをめくる感じのアプリが作りたくなりました。

github.com

よさげなパッケージがあったので、これを入れるだけで終わりか?と思って試してみました。

ネイティブでは普通に動きましたが、Webだとおかしくなってしまいました。

f:id:tnantoka:20191202212229p:plain

僕のFlutterのモチベーションのほとんどは「Webでもそのまま動く」が支えているので、Webで動かないと駄目なのです…。

パッケージの中身を修正するぐらいなら自前で書くか…と思っていたらStack Overflowにいい感じのサンプルがありました。

stackoverflow.com

それを簡略化したのが以下のコードです。

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {

  AnimationController _controller;
  Animation<double> _frontScale;
  Animation<double> _backScale;

  @override
  void initState() {
    super.initState();
    _controller = new AnimationController(
      vsync: this,
      duration: const Duration(seconds: 1),
    );
    _frontScale = new Tween(
      begin: 1.0,
      end: 0.0,
    ).animate(new CurvedAnimation(
      parent: _controller,
      curve: new Interval(0.0, 0.5, curve: Curves.easeIn),
    ));
    _backScale = new CurvedAnimation(
      parent: _controller,
      curve: new Interval(0.5, 1.0, curve: Curves.easeOut),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Stack(
          children: <Widget>[
            AnimatedBuilder(
              child: Container(
                height: 300,
                width: 300,
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.blue),
                  borderRadius: BorderRadius.circular(10),
                  color: Colors.grey[300],
                ),
              ),
              animation: _backScale,
              builder: (BuildContext context, Widget child) {
                final Matrix4 transform = Matrix4.identity()
                  ..scale(_backScale.value, 1.0, 1.0);
                return Transform(
                  transform: transform,
                  alignment: FractionalOffset.center,
                  child: child,
                );
              },
            ),
            AnimatedBuilder(
              child: Container(
                height: 300,
                width: 300,
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.blue),
                  borderRadius: BorderRadius.circular(10),
                  color: Colors.grey[100],
                ),
              ),
              animation: _frontScale,
              builder: (BuildContext context, Widget child) {
                final Matrix4 transform = Matrix4.identity()
                  ..scale(_frontScale.value, 1.0, 1.0);
                return Transform(
                  transform: transform,
                  alignment: FractionalOffset.center,
                  child: child,
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          if (_controller.isCompleted || _controller.velocity > 0) {
            _controller.reverse();
          } else {
            _controller.forward();
          }
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

これなら、ネイティブでもWebでもそのまま動きました。

f:id:tnantoka:20191202212541g:plain

これをベースに進めて行こうと思います。