简体   繁体   English

当控件在抖动中变得可见时,如何对其进行动画处理?

[英]How to animate a widget when it becomes visible in flutter?

I want to add some animations to some widgets in my app, but these widget are not visible until the user scroll down. 我想在我的应用程序的某些小部件中添加一些动画,但是直到用户向下滚动才能看到这些小部件。

I'd like for these animations to happen when the widget becomes visible, Generally I'd start the animation in initState but this only make the animation when the widget is first drawn, not when it becomes visible to the user . 我希望这些动画在小部件变得可见时发生,通常我会在initState启动动画,但这只会在第一次绘制小部件时才使动画产生,而在用户看不到它时才使动画initState

Is there any such event to listen to ? 有没有这样的事件要听? If not I imagine I can play with Viewport or aspect ratio or MediaQuery? 如果不是,我想我可以使用视口或宽高比或MediaQuery吗?

  1. Create a GlobalKey and an AnimationController for each of your widgets. 为每个小部件创建一个GlobalKey和一个AnimationController
  2. Use a ScrollController to listen for scroll events in your scroll view (doesn't have to be a ListView ) 使用ScrollController来监听滚动视图中的滚动事件(不必是ListView
  3. Use GlobalKey.currentContext.findRenderObject() to get the reference to the actual object that is rendered on screen. 使用GlobalKey.currentContext.findRenderObject()获取对在屏幕上呈现的实际对象的引用。
  4. If the RenderObject exists, get its relative position ( getTransformTo ) and check if the position is visible in the scroll view 如果RenderObject存在,请获取其相对位置( getTransformTo )并检查该位置在滚动视图中是否可见
  5. Start the animation. 开始动画。 To make sure that it is only triggered once, check the AnimationStatus of the AnimationController . 要确保仅触发一次,请检查AnimationStatusAnimationController

Example

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'),
          )
        ],
      ),
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM