如何在Flutter中为互换的小部件设置动画?

时间:2020-01-23 03:33:59

标签: animation flutter dart

我正在努力使自己实现扑朔迷离的以下设计。 该设计包括两个文本小部件和一个交换图标,单击它们时,两个文本小部件将以动画方式交换其位置。我尝试堆放并定位,但无法获取。

something similar

1 个答案:

答案 0 :(得分:4)

您可以使用Stack和Positioned交换两个小部件,最终添加动画效果。我举两个例子: 第一个代码只是交换了两个小部件。 第二个代码示例添加了动画效果。

交换两个小部件(无动画)

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  final double address1Top = 20;
  final double address2Top = 110;
  bool swapped = false;

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 150,
      color: Colors.blue,
      child: Stack(
        children: <Widget> [
          // Top address
          Positioned(
            top: swapped ? address2Top : address1Top,
            left: 20,
            child: Text("This is the first address"),
          ),
          // Bottom address
          Positioned(
            top: swapped ? address1Top : address2Top,
            left: 20,
            child: Text("This is another address"),
          ),
          // Swap button
          Positioned(
            top: 50,
            right: 20,
            child: FlatButton(
              onPressed: () => setState(() {
                swapped = !swapped;
              }),
              child: Text("swap"),
            ),
          ),
        ],
      ),
    );
  }
}

交换两个带有动画的小部件

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark(),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> with TickerProviderStateMixin {
  final double address1Top = 20;
  final double address2Top = 110;
  bool swapped = false;

  Animation<double> addressAnimation;
  AnimationController controller;
  animationListener() => setState(() { }); 

  @override
  void didChangeDependencies() async {
    super.didChangeDependencies();

    // Initialize animations
    controller = AnimationController(duration: const Duration(milliseconds: 300), vsync: this);

    addressAnimation = Tween(begin: 0.0, end: address2Top - address1Top).animate(CurvedAnimation(parent: controller, curve: const Interval(0.0, 1.0, curve: Curves.easeInOut)))..addListener(animationListener);
  }

  @override
  dispose() {
    // Dispose of animation controller
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    var tweenValue = addressAnimation?.value ?? 0.0;

    return Container(
      width: 300,
      height: 150,
      color: Colors.blue,
      child: Stack(
        children: <Widget> [
          // Top address
          Positioned(
            top: address1Top + tweenValue,
            left: 20,
            child: Text("This is the first address"),
          ),
          // Bottom address
          Positioned(
            top: address2Top - tweenValue,
            left: 20,
            child: Text("This is another address"),
          ),
          // Swap button
          Positioned(
            top: 50,
            right: 20,
            child: FlatButton(
              onPressed: () => setState(() {
                swapped ? controller.reverse() : controller.forward();
                swapped = !swapped;
              }),
              child: Text("swap"),
            ),
          ),
        ],
      ),
    );
  }
}

希望这会有所帮助:)