Reputation: 13
Help, I am trying to create a semi circular menu like this, image of what I want here
But I dont know how to place the widgets on top of the larger white line...I have tried using the following code. Please use the widget as the home widget in your main.dart and see the result. I have used the font_awesome_flutter package in packages pub for the icons:-
image of how it is currently here
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 Homewidgettoslack extends StatefulWidget {
Homewidgettoslack({
Key key,
}) : super(key: key);
@override
_HomewidgettoslackState createState() => _HomewidgettoslackState();
}
class _HomewidgettoslackState extends State<Homewidgettoslack> with TickerProviderStateMixin {
Animation<double> rotation;
Animation<double> translation;
Animation<double> menuscale;
AnimationController menuController;
@override
void initState() {
super.initState();
menuController =
AnimationController(duration: Duration(milliseconds: 900), vsync: this);
rotation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: menuController,
curve: Interval(
0.0,
0.7,
curve: Curves.decelerate,
),
),
);
translation = Tween<double>(
begin: 0.0,
end: 100.0,
).animate(
CurvedAnimation(parent: menuController, curve: Curves.elasticOut),
);
menuscale = Tween<double>(
begin: 1.5,
end: 0.0,
).animate(
CurvedAnimation(parent: menuController, curve: Curves.fastOutSlowIn),
);
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.blueGrey,
child: Scaffold(
backgroundColor: Colors.transparent,
body: Stack(
children: <Widget>[
Positioned(
left: -27,
right: -27,
top: 57,
bottom: 57,
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: CustomPaint(
painter: CurvedblacklinePainter(),
),
),
),
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: CustomPaint(
painter: CurvedblacklinePainter(),
),
),
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: AnimatedBuilder(
animation: menuController,
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(270,
color: Colors.pink, icon: FontAwesomeIcons.car),
_buildButton(315,
color: Colors.yellow, icon: FontAwesomeIcons.bolt),
Transform.scale(
scale: menuscale.value - 1,
child: FloatingActionButton(
child: Icon(FontAwesomeIcons.timesCircle),
onPressed: _close,
backgroundColor: Colors.red),
),
Transform.scale(
scale: menuscale.value,
child: FloatingActionButton(
child: Icon(
FontAwesomeIcons.solidDotCircle,
color: Colors.red,
),
onPressed: _open),
)
]),
);
},
),
),
],
),
),
);
}
_buildButton(double angle, {Color color, 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));
}
_open() {
print('OPEN CLICKED');
menuController.forward();
}
_close() {
print('CLOSE CLICKED');
menuController.reverse();
}
}
class CurvedblacklinePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = Colors.white
..strokeWidth = 1.8
..style = PaintingStyle.stroke;
Path path = Path();
path.moveTo(0, 0);
var secondEndPoint = Offset(0, size.height);
path.arcToPoint(secondEndPoint,
radius: Radius.circular((size.width / 2)),
clockwise: true,
largeArc: false);
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
Upvotes: 1
Views: 1358
Reputation: 2249
I improve your code and i fixed it as below ,
please replace my code with your code
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:vector_math/vector_math.dart' show radians, Vector3;
class Homewidgettoslack extends StatefulWidget {
Homewidgettoslack({
Key key,
}) : super(key: key);
@override
_HomewidgettoslackState createState() => _HomewidgettoslackState();
}
class _HomewidgettoslackState extends State<Homewidgettoslack>
with TickerProviderStateMixin {
Animation<double> rotation;
Animation<double> translationY;
Animation<double> translationX;
Animation<double> menuscale;
AnimationController menuController;
double _menuIconSize;
@override
void initState() {
super.initState();
menuController =
AnimationController(duration: Duration(milliseconds: 900), vsync: this);
rotation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: menuController,
curve: Interval(
0.0,
0.7,
curve: Curves.decelerate,
),
),
);
menuscale = Tween<double>(
begin: 1.5,
end: 0.0,
).animate(
CurvedAnimation(parent: menuController, curve: Curves.fastOutSlowIn),
);
}
@override
Widget build(BuildContext context) {
ScreenUtil.init(width: 360, height: 640, allowFontScaling: false);
_menuIconSize = ScreenUtil().setWidth(60);
double _bigCurveHeight = ScreenUtil().setHeight(520);
double _bigCurveWidth = ScreenUtil().setWidth(250);
translationY = Tween<double>(
begin: 0.0,
end: ((_bigCurveHeight / 2) - (_menuIconSize / 2)),
).animate(
CurvedAnimation(parent: menuController, curve: Curves.elasticOut),
);
translationX = Tween<double>(
begin: 0.0,
end: (_bigCurveWidth - (_menuIconSize / 2)),
).animate(
CurvedAnimation(parent: menuController, curve: Curves.elasticOut),
);
return Container(
color: Colors.blueGrey,
child: Scaffold(
backgroundColor: Colors.transparent,
body: Align(
alignment: Alignment.centerLeft,
child: Stack(
alignment: Alignment.centerLeft,
children: <Widget>[
Container(
height: _bigCurveHeight,
width: _bigCurveWidth,
child: CustomPaint(
painter: CurvedblacklinePainter(strokeWidth: 2),
),
),
Container(
height: ScreenUtil().setHeight(350),
width: ScreenUtil().setWidth(130),
child: CustomPaint(
painter: CurvedblacklinePainter(
strokeWidth: ScreenUtil().setWidth(60)),
),
),
Container(
child: AnimatedBuilder(
animation: menuController,
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(270,
color: Colors.pink, icon: FontAwesomeIcons.car),
_buildButton(315,
color: Colors.yellow, icon: FontAwesomeIcons.bolt),
Transform.scale(
scale: menuscale.value - 1,
child: FloatingActionButton(
child: Icon(FontAwesomeIcons.timesCircle),
onPressed: _close,
backgroundColor: Colors.red),
),
Transform.scale(
scale: menuscale.value,
child: FloatingActionButton(
child: Icon(
FontAwesomeIcons.solidDotCircle,
color: Colors.red,
),
onPressed: _open),
)
]),
);
},
),
),
],
),
),
),
);
}
_buildButton(double angle, {Color color, IconData icon}) {
final double rad = radians(angle);
return Transform(
transform: Matrix4.identity()
..translate(
(translationX.value) * cos(rad), (translationY.value) * sin(rad)),
child: FloatingActionButton(
child: Icon(icon),
backgroundColor: color,
onPressed: _close,
elevation: 0));
}
_open() {
print('OPEN CLICKED');
menuController.forward();
}
_close() {
print('CLOSE CLICKED');
menuController.reverse();
}
}
class CurvedblacklinePainter extends CustomPainter {
final double strokeWidth;
CurvedblacklinePainter({@required this.strokeWidth});
@override
void paint(Canvas canvas, Size size) {
Paint paint = new Paint()
..color = Colors.white
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
canvas.drawOval(
Rect.fromCenter(
center: Offset(-size.width / 2, size.height / 2),
width: size.width * 3,
height: size.height),
paint);
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return true;
}
}
and add dependency in your pubspec.yaml :
dev_dependencies:
flutter_test:
sdk: flutter
font_awesome_flutter: ^8.8.1
flutter_screenutil: ^2.1.0
result screenshot:
Upvotes: 2