Skip to content

Instantly share code, notes, and snippets.

@hardy716
Created January 28, 2024 18:24
Show Gist options
  • Save hardy716/c2985ed8e43991abd14812dd19f4044e to your computer and use it in GitHub Desktop.
Save hardy716/c2985ed8e43991abd14812dd19f4044e to your computer and use it in GitHub Desktop.
플러터챌린지 5일차 심화문제 - 신현호

플러터챌린지 5일차 심화문제 - 신현호

Created with <3 with dartpad.dev.

import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: ShootingStarScreen(),
));
}
class ShootingStarScreen extends StatefulWidget {
@override
State<ShootingStarScreen> createState() => _ShootingStarScreenState();
}
class _ShootingStarScreenState extends State<ShootingStarScreen> with TickerProviderStateMixin {
final List<_ShootingStarAnimation> _shootingStars = [];
int shootingCount = 0;
Color starColor = Colors.blue;
Color scoreBoxColor = Colors.black;
@override
void dispose() {
for (var star in _shootingStars) { star.dispose(); }
super.dispose();
}
void _shootAnimation() {
final shootingStar = _ShootingStarAnimation(context, this);
shootingStar.startAnimation();
_shootingStars.add(shootingStar);
Future.delayed(const Duration(milliseconds: 900), () {
setState(() {
shootingCount++;
scoreBoxColor = Colors.blue;
});
Future.delayed(const Duration(milliseconds: 100), () {
setState(() {
scoreBoxColor = Colors.black;
});
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('No matter what widgets are in the middle'),
Text('animation should not be obscured.'),
],
),
),
Positioned(
left: 10,
top: 80,
child: Container(
height: 50,
width: 50,
decoration: BoxDecoration(color: scoreBoxColor, shape: BoxShape.circle),
child: Center(
child: Text(
'$shootingCount',
style: const TextStyle(color: Colors.white),
),
),
),
),
Positioned(
right: 10,
bottom: 10,
child: ElevatedButton(
onPressed: _shootAnimation,
child: const Text('Shoot Star!')
),
),
]
),
);
}
}
class _ShootingStarAnimation {
late AnimationController _positionController;
late AnimationController _sizeController;
late Animation<Offset> _positionAnimation;
late Animation<double> _sizeAnimation;
late OverlayEntry overlayEntry;
BuildContext context;
TickerProvider vsync;
_ShootingStarAnimation(this.context, this.vsync) {
_positionController = AnimationController(
duration: const Duration(seconds: 1),
vsync: vsync,
);
_sizeController = AnimationController(
duration: const Duration(milliseconds: 500),
vsync: vsync,
);
_positionAnimation = Tween<Offset>(
begin: const Offset(1, 1),
end: const Offset(0, 0.05),
).animate(CurvedAnimation(
parent: _positionController,
curve: Curves.easeInOut,
));
_sizeAnimation = Tween<double>(
begin: 0,
end: 2.0,
).animate(CurvedAnimation(
parent: _sizeController,
curve: Curves.easeInOut,
));
overlayEntry = OverlayEntry(
builder: (context) => AnimatedBuilder(
animation: Listenable.merge([_positionAnimation, _sizeAnimation]),
builder: (context, child) {
return Positioned(
left: (MediaQuery.of(context).size.width) * _positionAnimation.value.dx,
top: (MediaQuery.of(context).size.height) * _positionAnimation.value.dy,
child: Transform.scale(
scale: _sizeAnimation.value,
child: const Icon(Icons.star, size: 30, color: Colors.blue),
),
);
},
),
);
_positionController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
overlayEntry.remove();
}
});
_sizeController.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_sizeController.reverse();
}
});
}
void startAnimation() {
Overlay.of(context).insert(overlayEntry);
_positionController.forward(from: 0.0);
_sizeController.forward(from: 0.0);
}
void dispose() {
_positionController.dispose();
_sizeController.dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment