Как развернуть и свернуть виджет, когда пользователь нажимает на другой виджет (родного или родного) с анимацией?

new Column(
    children: <Widget>[
        new header.IngridientHeader(
            new Icon(
                Icons.fiber_manual_record,
                color: AppColors.primaryColor
            ),
            'Voice Track 1'
        ),
        new Grid()
    ],
)

Я хочу, чтобы пользователь мог нажимать на header.IngridientHeader, а затем должен переключаться виджет Grid (скрыть, если он виден, и наоборот)

Редактировать:

Я пытаюсь сделать то, что в начальной загрузке называется Свернуть. getbootstrap.com/docs/4.0/components/collapse

Edit 2: header.IngridientHeader должен оставаться на месте все время, пока Grid () является прокручиваемым (горизонтальным) виджетом.

52
Dariusz Włodarz 28 Фев 2018 в 15:40

4 ответа

Лучший ответ

Если вы хотите свернуть виджет до нулевой высоты или нулевой ширины, у которой дочерний объект переполняется при свертывании, я бы порекомендовал SizeTransition или ScaleTransition.

Вот пример использования виджета ScaleTransition, чтобы свернуть контейнер для четырех черных кнопок и текста состояния. Мой виджет ExpandedSection используется со столбцом, чтобы получить следующую структуру. Пример виджета ScaleTransition

Пример виджета, который использует анимацию с виджетом SizeTransition:

class ExpandedSection extends StatefulWidget {

  final Widget child;
  final bool expand;
  ExpandedSection({this.expand = false, this.child});

  @override
  _ExpandedSectionState createState() => _ExpandedSectionState();
}

class _ExpandedSectionState extends State<ExpandedSection> with SingleTickerProviderStateMixin {
  AnimationController expandController;
  Animation<double> animation; 

  @override
  void initState() {
    super.initState();
    prepareAnimations();
    _runExpandCheck();
  }

  ///Setting up the animation
  void prepareAnimations() {
    expandController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500)
    );
    animation = CurvedAnimation(
      parent: expandController,
      curve: Curves.fastOutSlowIn,
    );
  }

  void _runExpandCheck() {
    if(widget.expand) {
      expandController.forward();
    }
    else {
      expandController.reverse();
    }
  }

  @override
  void didUpdateWidget(ExpandedSection oldWidget) {
    super.didUpdateWidget(oldWidget);
    _runExpandCheck();
  }

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

  @override
  Widget build(BuildContext context) {
    return SizeTransition(
      axisAlignment: 1.0,
      sizeFactor: animation,
      child: widget.child
    );
  }
}

AnimatedContainer также работает, но Flutter может пожаловаться на переполнение, если размер дочернего элемента не изменяется. до нулевой ширины или нулевой высоты.

45
Adam Jonsson 8 Дек 2019 в 06:48

В качестве альтернативы вы можете просто использовать AnimatedContainer, чтобы имитировать это поведение ,

enter image description here

class AnimateContentExample extends StatefulWidget {
  @override
  _AnimateContentExampleState createState() => new _AnimateContentExampleState();
}

class _AnimateContentExampleState extends State<AnimateContentExample> {
  double _animatedHeight = 100.0;
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text("Animate Content"),),
      body: new Column(
        children: <Widget>[
          new Card(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                new GestureDetector(
                  onTap: ()=>setState((){
                    _animatedHeight!=0.0?_animatedHeight=0.0:_animatedHeight=100.0;}),
                  child:  new Container(
                  child: new Text("CLICK ME"),
                  color: Colors.blueAccent,
                  height: 25.0,
                    width: 100.0,
                ),),
                new AnimatedContainer(duration: const Duration(milliseconds: 120),
                  child: new Text("Toggle Me"),
                  height: _animatedHeight,
                  color: Colors.tealAccent,
                  width: 100.0,
                )
              ],
            ) ,
          )
        ],
      ),
    );
  }
}
11
aziza 28 Фев 2018 в 16:47

< Сильный > Вывод :

enter image description here


< Сильный > Код:

class _HomePageState extends State<HomePage> {
  Duration _duration = Duration(seconds: 1);
  int _flex1 = 1, _flex2 = 1, _flex3 = 1;

  @override
  Widget build(BuildContext context) {
    var data = MediaQuery.of(context);
    double height = data.size.height - data.padding.top - kToolbarHeight;
    var height1 = (_flex1 * height) / (_flex1 + _flex2 + _flex3);
    var height2 = (_flex2 * height) / (_flex1 + _flex2 + _flex3);
    var height3 = (_flex3 * height) / (_flex1 + _flex2 + _flex3);

    return Scaffold(
      appBar: AppBar(
        title: Text("Awesome Effect"),
      ),
      body: Column(
        children: <Widget>[
          AnimatedContainer(
            duration: _duration,
            color: Colors.blue,
            height: height1,
            alignment: Alignment.center,
            child: Text("Flex: ${_flex1}", style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold)),
          ),
          AnimatedContainer(
            duration: _duration,
            color: Colors.red,
            height: height2,
            alignment: Alignment.center,
            child: Text("Flex: ${_flex2}", style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold)),
          ),
          AnimatedContainer(
            duration: _duration,
            color: Colors.teal,
            height: height3,
            alignment: Alignment.center,
            child: Text("Flex: ${_flex3}", style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold)),
          ),
        ],
      ),
    );
  }
}
2
CopsOnRoad 10 Окт 2019 в 18:06

Я думаю, что вы ищете ExpansionTile виджет. Это принимает свойство title, которое эквивалентно заголовку и свойству children, в которое вы можете передавать виджеты, которые будут показаны или скрыты при переключении. Вы можете найти пример того, как его использовать здесь.

Простой пример использования:

new ExpansionTile(title: new Text("Numbers"),
      children: <Widget>[
        new Text("Number: 1"),
        new Text("Number: 2"),
        new Text("Number: 3"),
        new Text("Number: 4"),
        new Text("Number: 5")
      ],
),

Надеюсь, это поможет!

5
Hemanth Raj 28 Фев 2018 в 13:41