Panduranga Rao Sadhu
Panduranga Rao Sadhu

Reputation: 497

How to animate interchanging widgets in Flutter?

I am trying to get my head around implementing the below design in flutter. The design consist of two text widgets and an interchange icon on clicking of which both the text widgets will swap their place animatedly. I tried stack and positioned but I could't get it.

something similar

Upvotes: 3

Views: 2798

Answers (1)

Alex Domenici
Alex Domenici

Reputation: 769

You can swap two widgets using Stack and Positioned, eventually adding an animation effect. I am giving two examples: the first code simply swaps the two widgets. the second code sample adds an animation effect.

Swap two widgets (no animation)

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

Swap two widgets with animation

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

Hope this helps :)

Upvotes: 10

Related Questions