import 'package:flutter/material.dart';
import 'dart:math';
import 'package:vector_math/vector_math.dart' show radians, Vector3;
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class App extends StatelessWidget {
const App({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter',
home: Scaffold(
body: SizedBox.expand(child: Stack(children: [Positioned(
top: 400,
left: 150,
child: RadialMenu())]))));
}
}
class RadialMenu extends StatefulWidget {
createState() => _RadialMenuState();
}
class _RadialMenuState extends State<RadialMenu> with SingleTickerProviderStateMixin {
late AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(duration: Duration(milliseconds: 900), vsync: this);
// ..addListener(() => setState(() {}));
}
@override
Widget build(BuildContext context) {
return RadialAnimation(key: UniqueKey(), controller: controller);
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
}
class RadialAnimation extends StatelessWidget {
RadialAnimation({ required Key key, required this.controller }) :
translation = Tween<double>(
begin: 0.0,
end: 100.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Curves.elasticOut
),
),
scale = Tween<double>(
begin: 1.5,
end: 0.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Curves.fastOutSlowIn
),
),
rotation = Tween<double>(
begin: 0.0,
end: 360.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.0, 0.7,
curve: Curves.decelerate,
),
),
),
super(key: key);
final AnimationController controller;
final Animation<double> rotation;
final Animation<double> translation;
final Animation<double> scale;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (context, widget) {
return Transform.rotate(
angle: radians(rotation.value),
child: Stack(
alignment: Alignment.center,
children: <Widget>[
_buildButton(0, color: Colors.red, icon: FontAwesomeIcons.thumbtack),
_buildButton(45, color: Colors.green, icon:FontAwesomeIcons.sprayCan),
_buildButton(90, color: Colors.orange, icon: FontAwesomeIcons.fire),
_buildButton(135, color: Colors.blue, icon:FontAwesomeIcons.kiwiBird),
_buildButton(180, color: Colors.black, icon:FontAwesomeIcons.cat),
_buildButton(225, color: Colors.indigo, icon:FontAwesomeIcons.paw),
_buildButton(270, color: Colors.pink, icon: FontAwesomeIcons.bong),
_buildButton(315, color: Colors.yellow, icon:FontAwesomeIcons.bolt),
Transform.scale(
scale: scale.value - 1,
child: FloatingActionButton(child: Icon(FontAwesomeIcons.timesCircle), onPressed: _close, backgroundColor: Colors.red),
),
Transform.scale(
scale: scale.value,
child: FloatingActionButton(child: Icon(FontAwesomeIcons.solidDotCircle), onPressed: _open),
)
])
);
});
}
_open() {
controller.forward();
}
_close() {
controller.reverse();
}
_buildButton(double angle, { required Color color, required IconData icon }) {
final double rad = radians(angle);
return Transform(
transform: Matrix4.identity()..translate(
(translation.value) * cos(rad),
(translation.value) * sin(rad)
),
child: FloatingActionButton(
child: Icon(icon), backgroundColor: color, onPressed: _close, elevation: 0)
);
}
}
CodePudding user response:
The Stack isn't blocking the buttons. Actually, it is not even aware of its children. When you apply the Matrix transformation to the buttons, you push them outside the Stack widget, which prevents them from receiving pointer events.
May not be an ideal workaround depending on your case, but providing the Stack a height and width will fix the issue. The buttons will remain within the boundaries of the Stack even after the transformation:
Stack(
alignment: Alignment.center,
children: <Widget>[
const SizedBox(height: 250, width: 250), // <== Add this line to the top
_buildButton(0, color: Colors.red, icon: Icons.clear),
_buildButton(45, color: Colors.green, icon: Icons.clear),
_buildButton(90, color: Colors.orange, icon: Icons.clear),
_buildButton(135, color: Colors.blue, icon: Icons.clear),
_buildButton(180, color: Colors.black, icon: Icons.clear),
_buildButton(225, color: Colors.indigo, icon: Icons.clear),
_buildButton(270, color: Colors.pink, icon: Icons.clear),
_buildButton(315, color: Colors.yellow, icon: Icons.clear),
Transform.scale(
scale: scale.value - 1,
child: FloatingActionButton(
child: Icon(Icons.clear),
onPressed: _close,
backgroundColor: Colors.red),
),
Transform.scale(
scale: scale.value,
child: FloatingActionButton(
child: Icon(Icons.clear), onPressed: _open),
)
],
)