在Flutter中设置小部件的动画位置

时间:2020-03-07 21:41:43

标签: flutter

我想动画图标小部件在屏幕上的位置。问题是直到整个屏幕构建完成后,我才知道小部件的结束位置。

此草图说明了我要实现的目标: enter image description here
图标应从屏幕中心开始,并在文本字段和按钮上方可用空间的中间结束。文本字段和按钮本身位于屏幕中央。

我该如何实现?

3 个答案:

答案 0 :(得分:1)

由于我之前不太了解您的问题,因此我已经更新了代码。

这是dartpad.dev上的更新代码,因此您可以看到它的外观和工作方式: https://dartpad.dev/74043837eaa459089fae03449fdc0778

这是代码:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        body: Center(
          child: LoginWidget(),
        ),
      ),
    );
  }
}

class LoginWidget extends StatefulWidget {
  const LoginWidget({
    Key key,
  }) : super(key: key);

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

class _LoginWidgetState extends State<LoginWidget> {
  @override
  initState() {
    initialTimer();
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
    super.initState();
  }

  GlobalKey _keyRed = GlobalKey();

  var gotPosition = false;
  var redPositionX;
  var redPositionY;
  var redWidth;
  var redHeight;

  _afterLayout(_) {
    _getPositions();
    _getSizes();
    setState(() {
      gotPosition = true;
    });
  }

  _getSizes() {
    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    final sizeRed = renderBoxRed.size;
    print("SIZE of Red: $sizeRed");
    redWidth = sizeRed.width;
    redHeight = sizeRed.height;
  }

  _getPositions() {
    print("beer");
    final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
    print(renderBoxRed);
    final positionRed = renderBoxRed.localToGlobal(Offset.zero);
    print("POSITION of Red: $positionRed ");
    redPositionY = positionRed.dy;
    redPositionX = positionRed.dx;
  }

  var startAnimation = false;
  initialTimer() async {
    await new Future.delayed(const Duration(milliseconds: 500));
    setState(() {
      startAnimation = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    var screenWidth = MediaQuery.of(context).size.width;
    var screenHeight = MediaQuery.of(context).size.height;
    print('width/height $screenWidth / $screenHeight');

    return Container(
      color: Colors.blue,
      child: Center(
        child: Stack(
          children: [
            Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                  margin: EdgeInsets.symmetric(horizontal: screenWidth * 0.3),
                  key: _keyRed,
                  color: Colors.red,
                  width: screenWidth * 0.4,
                  height: screenHeight * 0.2,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      Container(
                        color: Colors.yellow,
                        width: screenWidth * 0.3,
                        height: screenHeight * 0.05,
                      ),
                      Container(
                        color: Colors.yellow,
                        width: screenWidth * 0.3,
                        height: screenHeight * 0.05,
                      )
                    ],
                  ),
                ),
                // ),
              ],
            ),
            AnimatedPositioned(
              duration: Duration(seconds: 1),
              top: startAnimation
                  ? ((redPositionY / 2) - (redHeight / 2))
                  : redPositionY,
              curve: Curves.easeInCubic,
              left: 0.3 * screenWidth,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Container(
                    color: Colors.green,
                    width: screenWidth * 0.4,
                    height: screenHeight * 0.2,
                  ),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

差异和解释:

在此版本中,我使它尽可能地响应,并且能够使用全局键来选择红色框并获取其位置和大小。在渲染时间结束时,它会调用_afterLayout()来更新动画的信息,以便它从红色框开始,到一半结束。 (使用红色框的大小和位置中的数据。)

这对我来说是新手,所以我在这里依赖本教程: https://medium.com/@diegoveloper/flutter-widget-size-and-position-b0a9ffed9407,以了解如何处理小部件的大小和位置,以及如何管理在渲染结束时运行代码。

答案 1 :(得分:0)

这可以通过使用Hero动画来实现。如果我在两个屏幕中都使用Hero小部件包装并标记了图标小部件,则当使用导航器切换屏幕时,图标将自动设置动画。

答案 2 :(得分:-2)

看看这个: w3schools.com/css/css3_animations.asp

<!DOCTYPE html>
<html>
<head>
<style> 
div {
  width: 100px;
  height: 100px;
  background-color: red;
  position: relative;
  animation-name: example;
  animation-duration: 4s;
}

@keyframes example {
  0%   {background-color:red; left:0px; top:0px;}
  15%  {background-color:yellow; left:0px; top:100px;}
  
}
</style>
</head>
<body>

<p><b>Note:</b> This example does not work in Internet Explorer 9 and earlier versions.</p>

<div></div>

</body>
</html>