如何在颤动中动画崩溃元素

Dar*_*arz 7 dart flutter flutter-layout

当用户使用动画点击不同的小部件(兄弟或父级)时,如何展开和折叠小部件?

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

我希望用户能够点击header.IngridientHeader然后Grid小部件应该切换(隐藏,如果可见和其他方式)

编辑:

我试图做一些在引导程序中称为崩溃的东西.getbootstrap.com/docs/4.0/components/collapse

编辑2:header.IngridientHeader应始终保持原位Grid()是可滚动(水平)小部件.

Ada*_*son 21

如果你想折叠小部件零高度,或者有一个孩子倒塌溢出的时候,我会建议零宽度SizeTransitionScaleTransition

这是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();
  }

  ///Setting up the animation
  void prepareAnimations() {
    expandController = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 500)
    );
    Animation curve = CurvedAnimation(
      parent: expandController,
      curve: Curves.fastOutSlowIn,
    );
    animation = Tween(begin: 0.0, end: 1.0).animate(curve)
      ..addListener(() {
        setState(() {

        });
      }
    );
  }

  @override
  void didUpdateWidget(ExpandedSection oldWidget) {
    super.didUpdateWidget(oldWidget);
    if(widget.expand) {
      expandController.forward();
    }
    else {
      expandController.reverse();
    }
  }

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

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

AnimatedContainer也可以工作,但是如果不能将孩子的大小调整为零宽度或零高度,Flutter可能会抱怨溢出。

  • 我使用上面创建的小部件制作了一个 [working app](https://gist.github.com/AdamJonsson/57caa39ec3584343833ece556198187c) 类似于 gif 动画。不幸的是,我无法分享上述应用程序的特定代码,因为我不拥有该项目。 (6认同)
  • 我的项目需要这个,因此修改了此代码来制作 ExpandableSection 小部件。您可以自定义动画持续时间和曲线。注意:它需要 flutter_hooks 才能使用。https://gist.github.com/venkatd/b820b3b34b09239d85bf51ccb7f2278a (3认同)

Hem*_*Raj 11

我认为您正在寻找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")
      ],
),
Run Code Online (Sandbox Code Playgroud)

希望有帮助!


azi*_*iza 9

或者,您可以使用AnimatedContainer模仿此行为.

在此输入图像描述

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,
                )
              ],
            ) ,
          )
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 当孩子的身高不是常量时,AnimatedContainer 不适合。另一方面,[SizeTransition](/sf/ask/3432088901/#54173729)在这种情况下就像一个魅力。 (6认同)
  • 是的,除非它是一个“StatefulWidget”,否则“setState”不会起作用 (2认同)

Cop*_*oad 7

输出:

在此处输入图片说明


代码:

class FooPageState extends State<SoPage> {
  static const _duration = Duration(seconds: 1);
  int _flex1 = 1, _flex2 = 2, _flex3 = 1;

  @override
  Widget build(BuildContext context) {
    final total = _flex1 + _flex2 + _flex3;
    final height = MediaQuery.of(context).size.height;
    final height1 = (height * _flex1) / total;
    final height2 = (height * _flex2) / total;
    final height3 = (height * _flex3) / total;

    return Scaffold(
      body: Column(
        children: [
          AnimatedContainer(
            height: height1,
            duration: _duration,
            color: Colors.red,
          ),
          AnimatedContainer(
            height: height2,
            duration: _duration,
            color: Colors.green,
          ),
          AnimatedContainer(
            height: height3,
            duration: _duration,
            color: Colors.blue,
          ),
        ],
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Ans*_*kki 6

另一个不需要动画控制器的解决方案是使用AnimatedSwitcher小部件SizeTransition作为过渡构建器。

这是一个简单的例子:

AnimatedSwitcher(
  duration: Duration(milliseconds: 300),
  transitionBuilder: (child, animation) {
    return SizeTransition(sizeFactor: animation, child: child);
  },
  child: expanded ? YourWidget() : null,
)
Run Code Online (Sandbox Code Playgroud)

当然,您可以自定义动画的曲线和布局构建器。


小智 5

感谢@Adam Jonsson,他的回答解决了我的问题。这是关于如何使用ExpandedSection 的演示,希望对您有所帮助。

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);
  }
}
  
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Demo'),
        ),
        body: Home(),
      ),
    );
  }
}

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  bool _expand = false;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Header(
          onTap: () {
            setState(() {
              _expand = !_expand;
            });
          },
        ),
        ExpandedSection(child: Content(), expand: _expand,)
      ],
    );
  }
}

class Header extends StatelessWidget {
  final VoidCallback onTap;

  Header({@required this.onTap});

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        color: Colors.cyan,
        height: 100,
        width: double.infinity,
        child: Center(
          child: Text(
            'Header -- Tap me to expand!',
            style: TextStyle(color: Colors.white, fontSize: 20),
          ),
        ),
      ),
    );
  }
}

class Content extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.lightGreen,
      height: 400,
    );
  }
}
Run Code Online (Sandbox Code Playgroud)