32

i have something like this :

import 'package:flutter/material.dart';

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {
  bool loading = true;

  @override
  Widget build(BuildContext context) {
    if(loading) {
      return Container(
        color: Theme.of(context).scaffoldBackgroundColor,
        child: Center(
          child: SizedBox(
            width: 24,
            height: 24,
            child: GestureDetector(
              onTap: _toggle,
              child: CircularProgressIndicator(),
            ),
          ),
        ),
      );
    } else {
      return Container(
        child: Center(
          child: GestureDetector(
            onTap: _toggle,
            child: Text("WELCOME"),
          ),
        ),
      );
    }
  }

  _toggle() {
    setState(() {
      loading = !loading;
    });
  }
}

my big problem with flutter is animating between toggling widgets

i want when _toggle called, loading widget fadeOut and after animation completed remove from screen and then show normal widget with fadeIn effect

how can i achieved to this ?

thanks

DJafari
  • 12,955
  • 8
  • 43
  • 65
  • Have you take a look at [flutter sequence animation](https://pub.dartlang.org/packages/flutter_sequence_animation) package? – Miguel Ruivo Feb 09 '19 at 14:03
  • @miguelpruivo can you give a example with this package for my question ? – DJafari Feb 09 '19 at 14:09
  • https://docs.flutter.io/flutter/widgets/AnimatedCrossFade-class.html – anmol.majhail Feb 09 '19 at 14:34
  • Can you provide a simple mock for what you're trying to accomplish? – Miguel Ruivo Feb 09 '19 at 14:40
  • @anmol.majhail thanks. i saw this widgets before, when used this widget, when loading = false, loading widget position, changed from center to top, duration crossFade effect – DJafari Feb 09 '19 at 14:40
  • https://docs.flutter.io/flutter/widgets/AnimatedOpacity-class.html – user1462442 Feb 09 '19 at 14:46
  • @user1462442 thanks, but problem with this widget is when using fullscreen loading, after opacity = 0 this widget exist and prevent clickable of bellow layer – DJafari Feb 09 '19 at 14:48
  • Opacity widget only removes all events when its zero https://github.com/flutter/flutter/issues/10168 https://github.com/flutter/flutter/issues/10963 its a open bug – user1462442 Feb 09 '19 at 14:56
  • @user1462442 it's correct, but unfortunately currently this bug exists and can't help to me – DJafari Feb 09 '19 at 14:59
  • Hixie suggested ignore pointer https://github.com/flutter/flutter/issues/12283#issuecomment-332997209 should i write an answer? – user1462442 Feb 09 '19 at 15:00
  • May I ask why do you need a loading widget even thou you already have a fade in effect? – user1462442 Feb 09 '19 at 15:15
  • @user1462442 with your solution i think there is no need to fadeIn loading=false widget, if loading widget fadeIn and fadeOut it's enough, sure i could solve my problem with `IgnorePointer` widget, if you can't, i can write answer – DJafari Feb 09 '19 at 15:19

2 Answers2

58

Correct way is using AnimatedSwitcher widget:

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {
  bool loading = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: AnimatedSwitcher(
        duration: const Duration(milliseconds: 300),
        child: loading ? Container(
          key: Key("loading"),
          color: Theme.of(context).scaffoldBackgroundColor,
          child: Center(
            child: SizedBox(
              width: 24,
              height: 24,
              child: GestureDetector(
                onTap: _toggle,
                child: const CircularProgressIndicator(),
              ),
            ),
          ),
        ) : Container(
          key: Key("normal"),
          child: Center(
            child: GestureDetector(
              onTap: _toggle,
              child: const Text("WELCOME"),
            ),
          ),
        ),
      ),
    );
  }

  _toggle() {
    setState(() {
      loading = !loading;
    });
  }
}

note: you must give a key for children, in my example if you remove key animation not work

DJafari
  • 12,955
  • 8
  • 43
  • 65
  • Thanks for this suggestion, this was the easiest way ever. – Bawender Yandra Oct 07 '20 at 13:48
  • This is a good answer although I think adding a key is wrong. For me adding a key caused the widgets to fade in/out randomly when I setState. Works with out a UniqueKey(), don't use UniqueKey(). – Zog Apr 06 '21 at 23:37
  • 1
    Setting mandatory unique keys is very import for the animation to work. If keys are not provided it will not work. – Sisir Aug 27 '22 at 16:06
  • nicely ... awesome.. – Yogi Arif Widodo Jan 31 '23 at 01:42
  • Also make sure you're wrapping AnimatedSwitcher around the right widget. I was trying to wrap it around the most top level one and it didn't do any animation :) – Shalugin Apr 19 '23 at 10:30
17
import 'package:flutter/material.dart';

class MyWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _MyWidgetState();
  }
}

class _MyWidgetState extends State<MyWidget> {
  bool loading = true;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Stack(
        children: <Widget>[
          Center(
            child: GestureDetector(
              onTap: _toggle,
              child: Text("WELCOME"),
            ),
          ),
          IgnorePointer(
            ignoring: !loading,
            child: AnimatedOpacity(
              opacity: loading ? 1 : 0,
              duration: Duration(milliseconds: 500),
              child: Container(
                color: Theme.of(context).scaffoldBackgroundColor,
                child: Center(
                  child: SizedBox(
                    width: 24,
                    height: 24,
                    child: GestureDetector(
                      onTap: _toggle,
                      child: CircularProgressIndicator(),
                    ),
                  ),
                ),
              ),
            ),
          )
        ],
      ),
    );
  }

  _toggle() {
    setState(() {
      loading = !loading;
    });
  }
}
DJafari
  • 12,955
  • 8
  • 43
  • 65
user1462442
  • 7,672
  • 1
  • 24
  • 27