对于内圈,我使用Container 和Stack 来放置这些小部件。形状是使用ClipPath 制作的。
利用将圆形按钮放置为最后一个堆栈子项,因为 UI 优先考虑自下而上,
在dartpad 上运行。
路径
class BottomCentertPath extends CustomClipper<Path> {
@override
Path getClip(Size size) => Path()
..moveTo(size.width / 4, size.height)
..lineTo(size.width / 4 * 3, size.height)
..lineTo(size.width / 2, size.height / 2);
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
class BottomLeftPath extends CustomClipper<Path> {
@override
Path getClip(Size size) => Path()
..moveTo(size.width, size.height / 3 * 2)
..lineTo(size.width, size.height)
..lineTo(size.width / 4 * 3, size.height)
..lineTo(size.width / 2, size.height / 2);
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
class BottomRightPath extends CustomClipper<Path> {
@override
Path getClip(Size size) => Path()
..moveTo(0, size.height / 3 * 2)
..lineTo(0, size.height)
..lineTo(size.width / 4, size.height)
..lineTo(size.width / 2, size.height / 2);
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
class CenterRighttPath extends CustomClipper<Path> {
@override
Path getClip(Size size) => Path()
..moveTo(size.width, size.height / 3)
..lineTo(size.width / 2, size.height / 2)
..lineTo(size.width, size.height / 3 * 2);
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
class CenterLeftPath extends CustomClipper<Path> {
@override
Path getClip(Size size) => Path()
..moveTo(0, size.height / 3)
..lineTo(size.width / 2, size.height / 2)
..lineTo(0, size.height / 3 * 2);
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
class TopRightPath extends CustomClipper<Path> {
@override
Path getClip(Size size) => Path()
..moveTo(size.width / 2, 0)
..lineTo(size.width, 0)
..lineTo(size.width, size.height / 3)
..lineTo(size.width / 2, size.height / 2);
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
class TopLeftPath extends CustomClipper<Path> {
@override
Path getClip(Size size) => Path()
..lineTo(size.width / 2, 0)
..lineTo(size.width / 2, size.height / 2)
..lineTo(0, size.height / 3);
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}
测试小部件
class S7venIn1 extends StatelessWidget {
const S7venIn1({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(builder: (context, constraints) {
return Stack(
children: [
GestureDetector(
onTap: () {
debugPrint("TopLeftPath:");
},
child: ClipPath(
clipper: TopLeftPath(),
child: Container(
color: Colors.cyanAccent,
),
),
),
GestureDetector(
onTap: () {
debugPrint("TopRightPath:");
},
child: ClipPath(
clipper: TopRightPath(),
child: Container(
color: Colors.deepPurple,
),
),
),
GestureDetector(
onTap: () {
debugPrint("CenterLeftPath:");
},
child: ClipPath(
clipper: CenterLeftPath(),
child: Container(
color: Colors.deepOrange,
),
),
),
ClipPath(
clipper: CenterRighttPath(),
child: Container(
color: Colors.greenAccent,
),
),
GestureDetector(
onTap: () {
debugPrint("CenterRighttPath:");
},
child: ClipPath(
clipper: CenterRighttPath(),
child: Container(
color: Colors.greenAccent,
),
),
),
GestureDetector(
onTap: () {
debugPrint("BottomRightPath");
},
child: ClipPath(
clipper: BottomRightPath(),
child: Container(
color: Colors.indigoAccent,
),
),
),
GestureDetector(
onTap: () {
debugPrint("BottomCentertPath");
},
child: ClipPath(
clipper: BottomCentertPath(),
child: Container(
color: Colors.pinkAccent,
),
),
),
GestureDetector(
onTap: () {
debugPrint("BottomLeftPath");
},
child: ClipPath(
clipper: BottomLeftPath(),
child: Container(
color: Colors.amberAccent,
),
),
),
Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
debugPrint("Center Widget");
},
child: Container(
height: constraints.maxWidth * .25,
decoration: const BoxDecoration(
shape: BoxShape.circle, color: Colors.white),
),
),
)
],
);
}),
);
}
}
在CustomClipper<Path> 上播放大小。查看this 了解更多信息。
结果