Flutter (Dart):将屏幕分成 6 个部分,每个部分在中心有一个角

Flutter (Dart): Split the screen into 6 sections, each with one corner in the center

我正在尝试将屏幕分成 6 个 sections/parts,并满足以下要求:

我想在每个部分中都有一个单独的 GestureDetector。

有人知道用 Flutter & Dart 做这个的好方法吗?

示例图

对于内圈,我使用 Container and Stack to place those widgets. And shape is made using ClipPath

Make use to place the circle button as last stack child, because UI prioritize bottom to top,

运行 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 以了解更多信息。

结果