Where am I wrong in cheering up by showing and hiding widgets in the flutter?

Asked

Viewed 232 times

0

I made a list divided into two gridview because I wanted only the first 3 items to be displayed and with a button to display more items later. I don’t know if it was the right way to do it but it works for me.

But the method of displaying and hiding the items is very aggressive so I was able to put the animation for the items to appear, but I’m not able to make disappear with the fade. And then q appears the first time, even though I hide and make appear again the animation no longer works.

I would like to know how to make this animation work properly, and whether I’m on the right track in this way or should it all be differently.

That gif shows how this animation at the moment.

inserir a descrição da imagem aqui

I put the code on the dartpad for easy viewing:

https://dartpad.dev/526a5719cae7d8be0772f1e87ef02ced

And follow the whole code below too.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Test'),
        ),
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _MyWidget createState() => _MyWidget();
}

class _MyWidget extends State<MyWidget> with SingleTickerProviderStateMixin {
  AnimationController _animationController;
  Animation _animation;

  @override
  void initState() {
    _animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 800),
    );
    _animation = Tween(
      begin: 0.0,
      end: 1.0,
    ).animate(_animationController);
    super.initState();
  }

  @override
  dispose() {
    _animationController.dispose();
    super.dispose();
  }

  var _isExpanded = false;

  _toggleExpanded() {
    _animationController.forward();
    setState(() {
      _isExpanded = !_isExpanded;
    });
  }

  @override
  Widget build(BuildContext context) {

    return SingleChildScrollView(
      child: Column(children: <Widget>[
        GridView.builder(
          physics: NeverScrollableScrollPhysics(),
          shrinkWrap: true,
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
            childAspectRatio: 1.0,
            mainAxisSpacing: 0.0,
            crossAxisSpacing: 0.0,
          ),
          itemCount: 3,
          itemBuilder: (context, index) {
            return ItemCategory(
              title: "Teste $index",
              icon: Icons.apps,
              coloritem: Colors.deepPurple,
              onpressbtn: "teste $index",
            );
          },
        ),
        Visibility(
          visible: _isExpanded,
          child: FadeTransition(
            opacity: _animation,
            child: GridView.builder(
              physics: NeverScrollableScrollPhysics(),
              shrinkWrap: true,
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 3,
                childAspectRatio: 1.0,
                mainAxisSpacing: 0.0,
                crossAxisSpacing: 0.0,
              ),
              itemCount: 5,
              itemBuilder: (context, index) {
                var indx = index+3;
                return ItemCategory(
                  title: "Teste $indx",
                  icon: Icons.apps,
                  coloritem: Colors.deepPurple,
                  onpressbtn: "teste $index",
                );
              },
            ),
          ),
        ),
        IconButton(
          icon: _isExpanded
              ? Icon(Icons.keyboard_arrow_up)
              : Icon(Icons.keyboard_arrow_down),
          tooltip: 'Open More options',
          onPressed: _toggleExpanded,
        ),
      ]),
    );
  }
}

// Esses são itens de exemplo para ser exibido no gridview.
class ItemCategory extends StatelessWidget {
  ItemCategory({this.title, this.icon, this.coloritem, this.onpressbtn});

  final String title;
  final IconData icon;
  final MaterialColor coloritem;
  final String onpressbtn;

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.all(8.5),
      child: InkWell(
        onTap: () {},
        splashColor: Colors.amber,
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Icon(
                icon,
                size: 70.0,
                color: coloritem,
              ),
              Text(title, style: new TextStyle(fontSize: 17.0))
            ],
          ),
        ),
      ),
    );
  }
}

1 answer

1


So when this wrong is the order of execution, you call the animation before displaying the content, which breaks the sequence, first you must leave visible and then call the animation. And if you want to see the output animation in Reverse, the right thing to do is to use a system in the animation to see when the animation finished the version to close the Visible.

Your code would look like this.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      home: Scaffold(
        appBar: AppBar(
          title: Text('Test'),
        ),
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  _MyWidget createState() => _MyWidget();
}

class _MyWidget extends State<MyWidget> with SingleTickerProviderStateMixin {
  AnimationController _animationController;
  Animation _animation;

  @override
  void initState() {
    _animationController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 800),
    );
    _animation = Tween(
      begin: 0.0,
      end: 1.0,
    ).animate(_animationController);
    
    _animationController.addStatusListener((status){
      if(status == AnimationStatus.dismissed){
        setState(() {
            _isExpanded = false;
        });
      }
    });
    
    
    super.initState();
  }

  @override
  dispose() {
    _animationController.dispose();
    super.dispose();
  }

  var _isExpanded = false;

  _toggleExpanded() {
    
    if(_animationController.isDismissed){
      setState(() {
          _isExpanded = true;
      });
      _animationController.forward();
    }else{
      _animationController.reverse();
      
    }
    
  }

  @override
  Widget build(BuildContext context) {

    return SingleChildScrollView(
      child: Column(children: <Widget>[
        GridView.builder(
          physics: NeverScrollableScrollPhysics(),
          shrinkWrap: true,
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3,
            childAspectRatio: 1.0,
            mainAxisSpacing: 0.0,
            crossAxisSpacing: 0.0,
          ),
          itemCount: 3,
          itemBuilder: (context, index) {
            return ItemCategory(
              title: "Teste $index",
              icon: Icons.apps,
              coloritem: Colors.deepPurple,
              onpressbtn: "teste $index",
            );
          },
        ),
        Visibility(
          visible: _isExpanded,
          child: FadeTransition(
            opacity: _animation,
            child: GridView.builder(
              physics: NeverScrollableScrollPhysics(),
              shrinkWrap: true,
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 3,
                childAspectRatio: 1.0,
                mainAxisSpacing: 0.0,
                crossAxisSpacing: 0.0,
              ),
              itemCount: 5,
              itemBuilder: (context, index) {
                var indx = index+3;
                return ItemCategory(
                  title: "Teste $indx",
                  icon: Icons.apps,
                  coloritem: Colors.deepPurple,
                  onpressbtn: "teste $indx",
                );
              },
            ),
          ),
        ),
        IconButton(
          icon: _isExpanded
              ? Icon(Icons.keyboard_arrow_up)
              : Icon(Icons.keyboard_arrow_down),
          tooltip: 'Open More options',
          onPressed: _toggleExpanded,
        ),
      ]),
    );
  }
}

class ItemCategory extends StatelessWidget {
  ItemCategory({this.title, this.icon, this.coloritem, this.onpressbtn});

  final String title;
  final IconData icon;
  final MaterialColor coloritem;
  final String onpressbtn;

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.all(8.5),
      child: InkWell(
        onTap: () {},
        splashColor: Colors.amber,
        child: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Icon(
                icon,
                size: 70.0,
                color: coloritem,
              ),
              Text(title, style: new TextStyle(fontSize: 17.0))
            ],
          ),
        ),
      ),
    );
  }
}
  • Perfect, I didn’t know that status changed to dismissed only when animation closed, very interesting. I also didn’t know I should use Verse. By the logic I was looking for something like Ackwards. Thank you very much, I’ve been trying for days to understand that.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.