button_punch.dart 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:trackoffical_app/generated/assets.dart';
  4. import 'package:trackoffical_app/service/app.dart';
  5. import 'package:rive/rive.dart';
  6. import 'package:vibration/vibration.dart';
  7. class ButtonPunch extends StatefulWidget {
  8. const ButtonPunch({
  9. super.key,
  10. required this.onPressed,
  11. required this.isWarn,
  12. });
  13. final VoidCallback? onPressed;
  14. final bool isWarn;
  15. @override
  16. State<StatefulWidget> createState() {
  17. return ButtonPunchState();
  18. }
  19. }
  20. class ButtonPunchState extends State<ButtonPunch>
  21. with SingleTickerProviderStateMixin {
  22. late AnimationController _animationController;
  23. late Animation<Color?> _animation;
  24. var _isActive = true;
  25. @override
  26. void initState() {
  27. super.initState();
  28. _animationController = AnimationController(
  29. vsync: this,
  30. duration: const Duration(milliseconds: 500),
  31. reverseDuration: const Duration(milliseconds: 500),
  32. )..repeat(reverse: true);
  33. _animation = ColorTween(begin: Colors.white, end: Colors.red)
  34. .animate(_animationController)
  35. ..addListener(() {
  36. setState(() {
  37. // The state that has changed here is the animation object’s value.
  38. });
  39. });
  40. loopVibration();
  41. }
  42. Future<void> loopVibration() async{
  43. while(_isActive){
  44. await Future.delayed(500.milliseconds);
  45. if(widget.isWarn){
  46. await App.to.vibrate(duration: 100, repeat: 1);
  47. }
  48. }
  49. }
  50. @override
  51. void didUpdateWidget(covariant ButtonPunch oldWidget) {
  52. super.didUpdateWidget(oldWidget);
  53. final oldEnabled = oldWidget.onPressed != null;
  54. final newEnabled = widget.onPressed != null;
  55. if (oldEnabled != newEnabled) {
  56. if (newEnabled) {
  57. _animationController.repeat(reverse: true);
  58. } else {
  59. _animationController.stop();
  60. }
  61. }
  62. }
  63. @override
  64. void dispose() {
  65. _animationController.dispose();
  66. _isActive=false;
  67. super.dispose();
  68. }
  69. @override
  70. Widget build(BuildContext context) {
  71. final image = widget.onPressed != null? 'assets/images/btn_punch.png': 'assets/images/btn_punch_disable.png';
  72. final boxShadow = <BoxShadow>[];
  73. final children = <Widget>[];
  74. if(widget.isWarn){
  75. boxShadow.add(BoxShadow(
  76. color: Colors.red.withAlpha(150),
  77. offset: const Offset(0.0, 0.0), //阴影y轴偏移量
  78. blurRadius: 6, //阴影模糊程度
  79. spreadRadius: widget.onPressed!= null? 2: 1 //阴影扩散程度
  80. ));
  81. children.add(const RiveAnimation.asset(Assets.imagesAmPunchButtonFlash, fit: BoxFit.fill));
  82. }else{
  83. boxShadow.add(BoxShadow(
  84. color: Colors.grey.withAlpha(150),
  85. offset: const Offset(2.0, 2.0), //阴影y轴偏移量
  86. blurRadius: 6, //阴影模糊程度
  87. spreadRadius: widget.onPressed!= null? 5: 1 //阴影扩散程度
  88. ));
  89. }
  90. children.add(GestureDetector(
  91. onTap: widget.onPressed,
  92. child: Container(
  93. width: 56,
  94. height: 56,
  95. decoration: BoxDecoration(
  96. color: Colors.white,
  97. image: DecorationImage(
  98. image: AssetImage(image)),
  99. borderRadius: BorderRadius.circular(28),
  100. boxShadow: boxShadow,
  101. ),
  102. ),
  103. ));
  104. return SizedBox(height: 90, width: 90, child: Stack(
  105. alignment: Alignment.center,
  106. children: children,
  107. ));
  108. }
  109. }
  110. void main() async {
  111. runApp(Container(
  112. color: Colors.white,
  113. child: Column(
  114. children: [
  115. const Spacer(),
  116. ButtonPunch(
  117. onPressed: () { },
  118. isWarn: false,
  119. )
  120. ],
  121. ) )
  122. ) ;
  123. }