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

Viewed 190

I'm trying to split the screen into 6 sections/parts with the following requirements:

  • Each section should have a corner in the center of the screen (connected to the centered circle in the example drawing, see below).
  • Each section should be connected to the perimeter of the screen.

I want to have a separate GestureDetector in each of these sections.

Does anyone know any good ways to do this with Flutter & Dart?

example drawing

Link to example drawing

1 Answers

For Inner circle, I am using 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,

Run on dartpad.

Paths

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;
}

Test Widget


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),
                ),
              ),
            )
          ],
        );
      }),
    );
  }
}

Play with size on CustomClipper<Path>. Check this to learn more about it.

Result

enter image description here

Related