Created with <3 with dartpad.dev.
Created
January 28, 2024 18:24
-
-
Save hardy716/c2985ed8e43991abd14812dd19f4044e to your computer and use it in GitHub Desktop.
플러터챌린지 5일차 심화문제 - 신현호
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 '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