Poperton
Poperton

Reputation: 2196

How to animate the swap of 2 items in a Row?

I want to make something very simple. There's a Row with 2 widgets. When I press a button, they swap orders. I want this order swap to be animated.

I've loked at AnimatedPositioned but it requires a Stack. What would be the best way of doing such thing?

I thought Animating position across row cells in Flutter answered this but it's another different problem

Upvotes: 3

Views: 2121

Answers (1)

bluenile
bluenile

Reputation: 6029

You can easily animate widgets in a Row with SlideAnimation. Please see the code below or you may directly run the code on DartPad https://dartpad.dev/e5d9d2c9c6da54b3f76361eac449ce42 Just tap on the colored box to swap their positions with an slide animation.

SlideAnimation

Animates the position of a widget relative to its normal position.

The translation is expressed as an Offset scaled to the child's size. For example, an Offset with a dx of 0.25 will result in a horizontal translation of one quarter the width of the child.

import 'package:flutter/material.dart';

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

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

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  List<Animation<Offset>> _offsetAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 1),
      vsync: this,
    );
    _offsetAnimation = List.generate(
      2,
      (index) => Tween<Offset>(
        begin: const Offset(0.0, 0.0),
        end: Offset(index == 0 ? 1 : -1, 0.0),
      ).animate(_controller),
    );
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  void _animate() {
    _controller.status == AnimationStatus.completed
        ? _controller.reverse()
        : _controller.forward();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Flutter Demo Row Animation")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                BoxWidget(
                  callBack: _animate,
                  text: "1",
                  color: Colors.red,
                  position: _offsetAnimation[0],
                ),
                BoxWidget(
                  callBack: _animate,
                  text: "2",
                  color: Colors.blue,
                  position: _offsetAnimation[1],
                )
              ],
            ),
            RaisedButton(
              onPressed: _animate,
              child: const Text("Swap"),
            )
          ],
        ),
      ),
    );
  }
}

class BoxWidget extends StatelessWidget {
  final Animation<Offset> position;
  final Function callBack;
  final String text;
  final Color color;

  const BoxWidget(
      {Key key, this.position, this.callBack, this.text, this.color})
      : super(key: key);
  @override
  Widget build(BuildContext context) {
    return SlideTransition(
      position: position,
      child: GestureDetector(
        onTap: () => callBack(),
        child: Container(
          margin: const EdgeInsets.all(10),
          height: 50,
          width: 50,
          color: color,
          child: Center(
            child: Container(
              height: 20,
              width: 20,
              decoration: const BoxDecoration(
                shape: BoxShape.circle,
                color: Colors.white,
              ),
              child: Center(child: Text(text)),
            ),
          ),
        ),
      ),
    );
  }
}

Upvotes: 11

Related Questions