Created
March 26, 2020 17:58
-
-
Save filiph/6c88ebe0da89eb514a551ee44527e54a to your computer and use it in GitHub Desktop.
Orbiting containers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:math'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter/rendering.dart'; | |
void main() => runApp(MyApp()); | |
class MyApp extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
theme: ThemeData( | |
primarySwatch: Colors.blue, | |
), | |
home: MyHomePage(), | |
); | |
} | |
} | |
final _random = Random(); | |
class MyHomePage extends StatefulWidget { | |
@override | |
_MyHomePageState createState() => _MyHomePageState(); | |
} | |
class _MyHomePageState extends State<MyHomePage> { | |
int _count = 50; | |
@override | |
Widget build(BuildContext context) { | |
final random = Random(42); | |
return Scaffold( | |
backgroundColor: Color(0xFFdddddd), | |
appBar: AppBar( | |
title: Text('Flutter Demo Home Page'), | |
), | |
body: Stack( | |
children: <Widget>[ | |
for (var i = 0; i < _count; i++) | |
Positioned( | |
key: ValueKey(i), | |
left: random.nextDouble() * 320 - 20, | |
top: random.nextDouble() * 600 - 10, | |
child: MyOrbitingCard(i), | |
), | |
], | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: () => setState(() => _count += 10), | |
tooltip: 'Increment', | |
child: Icon(Icons.add), | |
), | |
); | |
} | |
} | |
class MyOrbitingCard extends StatefulWidget { | |
final int i; | |
MyOrbitingCard(this.i); | |
@override | |
_MyOrbitingCardState createState() => _MyOrbitingCardState(); | |
} | |
class _MyOrbitingCardState extends State<MyOrbitingCard> | |
with SingleTickerProviderStateMixin { | |
AnimationController _controller; | |
Animation<Offset> _offsetAnimation; | |
@override | |
void initState() { | |
super.initState(); | |
_controller = AnimationController( | |
duration: Duration(milliseconds: 600 + widget.i * 60), vsync: this); | |
_controller.repeat(); | |
_offsetAnimation = OrbitTween(1).animate(_controller); | |
} | |
@override | |
void dispose() { | |
_controller?.dispose(); | |
super.dispose(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return SlideTransition( | |
position: _offsetAnimation, | |
child: MyCard(widget.i), | |
); | |
} | |
} | |
class OrbitTween extends Tween<Offset> { | |
final double distance; | |
OrbitTween(this.distance) | |
: super(begin: Offset(distance, 0), end: Offset(distance, 0)); | |
@override | |
Offset lerp(double t) { | |
return Offset.fromDirection(t * 2 * pi, distance); | |
} | |
} | |
class MyCard extends StatelessWidget { | |
final int i; | |
MyCard(this.i); | |
@override | |
Widget build(BuildContext context) { | |
return Material( | |
shape: RoundedRectangleBorder( | |
side: BorderSide(), | |
borderRadius: BorderRadius.circular(6), | |
), | |
color: Colors.white, | |
child: Padding( | |
padding: const EdgeInsets.all(8.0), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Row( | |
children: <Widget>[ | |
Text('Card #${i + 1}'), | |
SizedBox(width: 8), | |
SizedBox( | |
width: 16, | |
height: 16, | |
child: Container( | |
color: Colors | |
.primaries[_random.nextInt(Colors.primaries.length)]), | |
) | |
], | |
), | |
SizedBox(height: 8), | |
SizedBox( | |
width: 150, | |
height: 1, | |
child: Container(color: Colors.black54), | |
), | |
SizedBox(height: 8), | |
Text('Lorem ipsum dolor\nsit amet.') | |
], | |
), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment