我的应用程序是一个简单的专栏,有3个文本小部件,用幻灯片翻译.我的目标是让应用程序加载时屏幕上没有任何内容,然后将这些文本小部件从底部(屏幕外)向上移动到屏幕(中间).

return Column(
   children: <Widget>[
     SlideTransition(
         position:_curve1,
         child: Text('Hello 1')
     ),
     SlideTransition(
         position:_curve1,
         child: Text('Hello 2')
     ),
     SlideTransition(
         position:_curve1,
         child: Text('Hello 3')
     ),
   ]
);

问题是在定义动画时,必须指定它们的初始偏移.

@override
void initState(){
    ...
    Offset beginningOffset = Offset(0.0,20.0);
    _curve1 = Tween<Offset>(begin: beginningOffset, end: Offset.zero).animate(
    CurvedAnimation(
        parent: _animationController,
        curve: Curves.easeInOut)));
    ...
}  

在这里您可以看到,starinningOffset被指定为偏移量(0.0,20.0),这确实成功地将小部件定位在屏幕之外.但是如果我突然在平板电脑上运行会发生什么呢?由于偏移量被定义为小部件高度的单位,因此这显然不是将小部件定位在屏幕外的好方法.

由于动画是在"initState()"中定义的...我认为没有办法使用MediaQuery之类的东西.关于(上下文)...因为我们没有上下文.

在本机IOS中,这会很简单.在"viewDidLoad"中,您将从self.view获得帧.您需要将每个文本字段明确定位在框架的边缘.然后设置约束更改的动画,将它们放置在所需的位置.为什么这要这么艰难地Flutter 呢?

我发现特别奇怪的是,在我能找到的任何例子中都完全没有涉及到这个确切的场景(在屏幕外开始一个动画).例如:

https://github.com/flutter/website/blob/master/examples/_animation/basic_staggered_animation/main.dart

似乎几乎所有类型的动画在这里都有特色,除了一个显式的屏幕外动画在加载…也许我只是错过了什么.

编辑:花生已经解决了这个问题!判断他的"第二次更新".

推荐答案

您可能希望try 在initState中使用addPostFrameCallback方法.

    @override
    void initState() {
      super.initState();
      WidgetsBinding.instance.addPostFrameCallback((_){
         // Schedule code execution once after the frame has rendered
         print(MediaQuery.of(context).size.toString());
      });
    }

Flutter Api Docs Link

OR您也可以使用Future来执行以下操作:

    @override
    void initState() {
      super.initState();
      new Future.delayed(Duration.zero, () {
          // Schedule a zero-delay future to be executed
          print(MediaQuery.of(context).size.toString());
      });
    }

希望这有帮助.

UPDATED

这有点像是unusual种方式,但它真的做到了你需要的东西.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
  Animation<Offset> animation;
  AnimationController animationController;

  @override
  void initState() {
    super.initState();

    animationController = AnimationController(
      vsync: this,
      duration: Duration(seconds: 2),
    );
    animation = Tween<Offset>(
      begin: Offset(0.0, 1.0),
      end: Offset(0.0, 0.0),
    ).animate(CurvedAnimation(
      parent: animationController,
      curve: Curves.fastLinearToSlowEaseIn,
    ));

    Future<void>.delayed(Duration(seconds: 1), () {
      animationController.forward();
    });
  }

  @override
  void dispose() {
    // Don't forget to dispose the animation controller on class destruction
    animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Stack(
        alignment: Alignment.center,
        fit: StackFit.expand,
        children: <Widget>[
          SlideTransition(
            position: animation,
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                CircleAvatar(
                  backgroundImage: NetworkImage(
                    'https://pbs.twimg.com/media/DpeOMc3XgAIMyx_.jpg',
                  ),
                  radius: 50.0,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

它是这样工作的:

1.我们创建了一个包含Stack个项目的列表,其中包含展开其中任何子项的选项.

2.将要显示的每个slide包装为Column,子项居中对齐.该列将占用堆栈大小的2.%.

3.将动画的开始Offset设置为Offset(0.0, 1.0).

请记住,偏移量中的dxdy不是像素或类似的东西,而是Widget's宽度或高度的比率.例如:如果你的widget's width is 100.0,你把0.25 as dx,它将result in moving your child to the right by 25.0 points.

因此,将偏移量设置为(0.0,1.0)会将列从屏幕移到底部100%的高度(这是在Flutter 中工作的页面过渡的数量).

4美元.在延迟1秒后将柱动画恢复到其原始位置.

SECOND UPDATE

此代码根据屏幕大小和小部件大小计算偏移量. 我不知道有没有更好的方法来做这件事.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Page(),
    );
  }
}

class Page extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _PageState();
}

class _PageState extends State<Page> with SingleTickerProviderStateMixin {
  // Set the initial position to something that will be offscreen for sure
  Tween<Offset> tween = Tween<Offset>(
    begin: Offset(0.0, 10000.0),
    end: Offset(0.0, 0.0),
  );
  Animation<Offset> animation;
  AnimationController animationController;

  GlobalKey _widgetKey = GlobalKey();

  @override
  void initState() {
    super.initState();

    // initialize animation controller and the animation itself
    animationController = AnimationController(
      vsync: this,
      duration: Duration(seconds: 2),
    );
    animation = tween.animate(animationController);

    Future<void>.delayed(Duration(seconds: 1), () {
      // Get the screen size
      final Size screenSize = MediaQuery.of(context).size;
      // Get render box of the widget
      final RenderBox widgetRenderBox =
          _widgetKey.currentContext.findRenderObject();
      // Get widget's size
      final Size widgetSize = widgetRenderBox.size;

      // Calculate the dy offset.
      // We divide the screen height by 2 because the initial position of the widget is centered.
      // Ceil the value, so we get a position that is a bit lower the bottom edge of the screen.
      final double offset = (screenSize.height / 2 / widgetSize.height).ceilToDouble();

      // Re-set the tween and animation
      tween = Tween<Offset>(
        begin: Offset(0.0, offset),
        end: Offset(0.0, 0.0),
      );
      animation = tween.animate(animationController);

      // Call set state to re-render the widget with the new position.
      this.setState((){
        // Animate it.
        animationController.forward();
      });
    });
  }

  @override
  void dispose() {
    // Don't forget to dispose the animation controller on class destruction
    animationController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: Alignment.center,
      fit: StackFit.loose,
      children: <Widget>[
        SlideTransition(
          position: animation,
          child: CircleAvatar(
            key: _widgetKey,
            backgroundImage: NetworkImage(
              'https://pbs.twimg.com/media/DpeOMc3XgAIMyx_.jpg',
            ),
            radius: 50.0,
          ),
        ),
      ],
    );
  }
}

Dart相关问答推荐

为具有通用函数字段的Generic类实现copyWith

程序给出不准确的值

Dart 中的const关键字放置有什么不同?

您如何在元素中设置自定义元素标签的样式?

Dart/Flutter ffi(外部函数接口)本机回调,例如:sqlite3_exec

Dart JavaScript 与 jQuery 的互操作回调

Dart 捕获 http 异常

Flutter Text 小部件中的 StrutStyle 是什么

用百分比将小部件放置在堆栈中

Flutter url_launcher 未在发布模式下启动 url

如何将 转换为 List

Dart 2:Future 和 Future 之间的区别

扩展一个只有一个工厂构造函数的类

在 Dart 中编写单元测试的最佳方式是什么?

有可用的 Dart VM 吗?

如何在 Ubuntu 网络服务器上为 Dart 安装 pub(命令行使用)

在 Dart 中是否允许在 for 循环中等待?

判断 datetime 变量是今天、明天还是昨天

在 Dart 中没有换行符的 print()?

如何在 Dart 中将日期/时间字符串转换为 DateTime 对象?