【问题标题】:How to animate a widget when it becomes visible in flutter?当小部件在颤动中可见时如何为小部件设置动画?
【发布时间】:2023-03-06 23:57:01
【问题描述】:

我想为我的应用中的一些小部件添加一些动画,但这些小部件在用户向下滚动之前是不可见的。

我希望这些动画在小部件变得可见时发生,通常我会在 initState 中启动动画,但这只会在小部件第一次绘制时制作动画,而不是在它对用户可见时.

有没有这样的活动可以听?如果不是,我想我可以使用 Viewport 或纵横比或 MediaQuery?

【问题讨论】:

    标签: flutter


    【解决方案1】:
    1. 为每个小部件创建一个GlobalKey 和一个AnimationController
    2. 使用ScrollController 监听滚动视图中的滚动事件(不必是ListView
    3. 使用GlobalKey.currentContext.findRenderObject() 获取对屏幕上呈现的实际对象的引用。
    4. 如果RenderObject 存在,则获取其相对位置(getTransformTo)并检查该位置是否在滚动视图中可见
    5. 开始动画。要确保它只触发一次,请检查AnimationControllerAnimationStatus

    示例

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Playground',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new TestPage(),
        );
      }
    }
    
    class TestPage extends StatefulWidget {
      @override
      _TestPageState createState() => new _TestPageState();
    }
    
    class _TestPageState extends State<TestPage> with SingleTickerProviderStateMixin {
      final listViewKey = new GlobalKey();
      final animatedBoxKey = new GlobalKey();
    
      final scrollController = new ScrollController();
    
      AnimationController animatedBoxEnterAnimationController;
    
      @override
      void initState() {
        super.initState();
    
        animatedBoxEnterAnimationController = new AnimationController(
          vsync: this,
          duration: Duration(milliseconds: 2000),
        );
    
        scrollController.addListener(() {
          _updateAnimatedBoxEnterAnimation();
        });
      }
    
      static const enterAnimationMinHeight = 100.0;
    
      _updateAnimatedBoxEnterAnimation() {
        if (animatedBoxEnterAnimationController.status != AnimationStatus.dismissed) {
          return; // animation already in progress/finished
        }
    
        RenderObject listViewObject = listViewKey.currentContext?.findRenderObject();
        RenderObject animatedBoxObject = animatedBoxKey.currentContext?.findRenderObject();
        if (listViewObject == null || animatedBoxObject == null) return;
    
        final listViewHeight = listViewObject.paintBounds.height;
        final animatedObjectTop = animatedBoxObject.getTransformTo(listViewObject).getTranslation().y;
    
        final animatedBoxVisible = (animatedObjectTop + enterAnimationMinHeight < listViewHeight);
    
        if (animatedBoxVisible) {
          // start animation
          animatedBoxEnterAnimationController.forward();
        }
      }
    
      @override
      Widget build(BuildContext context) {
        final boxOpacity = CurveTween(curve: Curves.easeOut).animate(animatedBoxEnterAnimationController);
    
        final boxPosition = Tween(begin: Offset(-1.0, 0.0), end: Offset.zero)
            .chain(CurveTween(curve: Curves.elasticOut))
            .animate(animatedBoxEnterAnimationController);
    
        return new Scaffold(
          appBar: new AppBar(
            title: new Text('Flutter Playground'),
          ),
          body: new ListView(
            key: listViewKey,
            controller: scrollController,
            children: <Widget>[
              new Container(
                padding: EdgeInsets.all(16.0),
                child: new Text(
                  'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
                  style: TextStyle(fontSize: 24.0),
                ),
              ),
              new FadeTransition(
                opacity: boxOpacity,
                child: new SlideTransition(
                  position: boxPosition,
                  child: new Container(
                    key: animatedBoxKey,
                    height: 300.0,
                    color: Colors.green,
                    padding: EdgeInsets.all(16.0),
                    child: new Text('Animated Box'),
                  ),
                ),
              ),
              new Container(
                padding: EdgeInsets.all(16.0),
                child: new Text(
                  'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
                  style: TextStyle(fontSize: 24.0),
                ),
              ),
              new FlatButton(
                onPressed: () {
                  scrollController.jumpTo(0.0);
                  animatedBoxEnterAnimationController.reset();
                },
                child: new Text('Reset'),
              )
            ],
          ),
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-03
      • 2021-11-28
      • 1970-01-01
      • 2020-12-14
      • 2018-12-02
      • 1970-01-01
      • 2019-07-30
      • 1970-01-01
      相关资源
      最近更新 更多