use*_*745 3 flutter flutter-layout
我正在尝试绘制一个圆形菜单,如下图所示,但是我是 Flutter 新手,我不知道从哪里开始这样的操作。
我只会有 8 个和平,而不是图中所示的 12 个,它们都是链接,每个链接都指向应用程序的不同部分。
在中心灰色区域,我们将有短文本
我希望它能提供一些开始。
脚步:
Path包来创建fluttersvg pathShapeDecoration或ClipPath,我选择了ClipPath,但ShapeDecoration可以添加阴影。Matrix4或旋转Path。Transform.rotate我选择了“Transform.rotate 两次”,它速度更快,但使用Path.transform是更干净的方法。快乐编码!享受!
ps 如果我们做没有具体数量的解决方案可能会更好。
示例代码:
import 'dart:math' as math;
import 'package:flutter/material.dart';
const double degrees2Radians = math.pi / 180.0;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
backgroundColor: Colors.amber,
body: SafeArea(
child: MyHomePage(),
),
),
);
}
}
class MyHomePage extends StatelessWidget {
final items = [
ButtonData(title: 'one', onTap: () => print('1')),
ButtonData(title: 'two', onTap: () => print('2')),
ButtonData(title: 'three', onTap: () => print('3')),
ButtonData(title: 'four', onTap: () => print('4')),
ButtonData(title: 'five', onTap: () => print('5')),
ButtonData(title: 'six', onTap: () => print('6')),
ButtonData(title: 'seven', onTap: () => print('7')),
ButtonData(title: 'eight', onTap: () => print('8')),
ButtonData(onTap: () => print('center')),
];
@override
Widget build(BuildContext context) {
return Container(
height: 300,
width: 300,
child: Stack(
children: items
.asMap()
.map((index, buttonData) {
if (index < 8) {
var degree = 360 / 8 * index;
var radian = degree * degrees2Radians;
return MapEntry(
index,
Align(
alignment: Alignment(
math.sin(radian),
math.cos(radian),
),
child: Transform.rotate(
angle: -radian,
child: MenuPetal(angle: -radian, buttonData: buttonData),
),
),
);
}
return MapEntry(
index,
_centerButton(buttonData),
);
})
.values
.toList(),
),
);
}
Widget _centerButton(ButtonData buttonData) {
return Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(25),
child: GestureDetector(
onTap: buttonData.onTap,
child: Container(
width: 50,
height: 50,
color: Colors.black38,
),
),
),
);
}
}
class ButtonData {
final String? title;
final void Function()? onTap;
ButtonData({this.title, this.onTap});
}
class MenuPetal extends StatelessWidget {
const MenuPetal({
super.key,
required this.angle,
required this.buttonData,
});
final double angle;
final ButtonData buttonData;
final double factor = 0.38;
@override
Widget build(BuildContext context) {
return FractionallySizedBox(
heightFactor: factor,
widthFactor: factor,
child: GestureDetector(
onTap: buttonData.onTap,
child: ClipPath(
clipper: MyCustomClipper(),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image:
NetworkImage('https://source.unsplash.com/featured/?white'),
),
),
child: Padding(
padding: EdgeInsets.only(top: 60),
child: Transform.rotate(
angle: -angle,
child: Text(buttonData.title ?? ""),
),
),
),
),
),
);
}
}
class MyCustomClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var x = size.width / 100 * 0.802;
var y = size.height / 100;
var path = Path()
..moveTo(39.4 * x, 6.1 * y)
..cubicTo(43.2 * x, -1.8 * y, 57.1 * x, -1.8 * y, 60.9 * x, 6.1 * y)
..lineTo(99.1 * x, 84.1 * y)
..cubicTo(102.1 * x, 90.2 * y, 99.1 * x, 93.9 * y, 92.0 * x, 95.6 * y)
..cubicTo(67.4 * x, 101.7 * y, 36.9 * x, 101.7 * y, 9.2 * x, 95.6 * y)
..cubicTo(1.2 * x, 93.8 * y, -1.3 * x, 88.7 * y, 1.2 * x, 84.1 * y)
..lineTo(39.4 * x, 6.1 * y);
return path.shift(Offset(12, 0));
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1868 次 |
| 最近记录: |