Reputation: 497
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.
Upvotes: 3
Views: 2798
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