2

I want to create a Widget with 2 container using a CustomClipper and add a line/stroke/border between them like:

enter image description here

So I want a bottom border on the red colored Container, that is in between the red and the yellow container. I am able to add the clip path with a custom clipper, but I don't know how can I add a line in between these two container.

My current widget is:

Container(
      margin: const EdgeInsetsDirectional.only(end: 8),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(6),
        child: Stack(
          children: [
            Align(
              alignment: AlignmentDirectional.bottomCenter,
              child: Container(
                decoration: BoxDecoration(
                    color: Colors.yellow, border: Border.all(color: AppColors.instance.color0B0B0B, width: 1), borderRadius: const BorderRadius.all(Radius.circular(6))),
                height: 200,
                child: const Center(
                  child: Text("Hello"),
                ),
              ),
            ),
            Align(
              alignment: AlignmentDirectional.topCenter,
              child: ClipPath(
                clipper: MyClipper(),
                child: Container(
                  decoration: BoxDecoration(
                      color: Colors.red, border: Border.all(color: AppColors.instance.color0B0B0B, width: 1), borderRadius: const BorderRadius.all(Radius.circular(6))),
                  height: 200,
                  child: const Center(
                    child: Text("Hello Hello"),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    )

and the custom clipper class is:

class MyClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    int curveHeight = 60;
    Offset controlPoint = Offset(size.width / 2, size.height + curveHeight);
    Offset endPoint = Offset(size.width, size.height - curveHeight);

    Path path = Path()
      ..lineTo(0, size.height - curveHeight)
      ..quadraticBezierTo(controlPoint.dx, controlPoint.dy, endPoint.dx, endPoint.dy)
      ..lineTo(size.width, 0)
      ..close();

    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}

If somebody have any other good idea, please correct me. Thanks in advance!

Tech Nerd
  • 822
  • 1
  • 13
  • 39

2 Answers2

0

You can include another ClipPath on same position as red container with increasing its height a little but up.

height: 200 + 5, // main height + border

   body: LayoutBuilder(
        builder: (context, constraints) {
          return Center(
            child: Container(
              height: constraints.maxHeight,
              margin: const EdgeInsetsDirectional.only(end: 8),
              child: ClipRRect(
                borderRadius: BorderRadius.circular(6),
                child: Stack(
                  children: [
                    Align(
                      alignment: AlignmentDirectional.bottomCenter,
                      child: Container(
                        decoration: BoxDecoration(
                            color: Colors.yellow,
                            border: Border.all(
                                // color: AppColors.instance.color0B0B0B,
                                width: 1),
                            borderRadius:
                                const BorderRadius.all(Radius.circular(6))),
                        height: constraints.maxHeight / 2,
                        child: const Center(
                          child: Text("Hello"),
                        ),
                      ),
                    ),

                    ///border color
                    Align(
                      alignment: AlignmentDirectional.topCenter,
                      child: ClipPath(
                        clipper: MyClipper(),
                        child: Container(
                          decoration: BoxDecoration(
                              color: Color.fromARGB(255, 38, 240, 16),
                              borderRadius:
                                  const BorderRadius.all(Radius.circular(6))),
                          height: constraints.maxHeight * .65 +
                              5, //  main height + border
                        ),
                      ),
                    ),
                    Align(
                      alignment: AlignmentDirectional.topCenter,
                      child: ClipPath(
                        clipper: MyClipper(),
                        child: Container(
                          decoration: const BoxDecoration(
                            color: Colors.red,
                            borderRadius: BorderRadius.all(
                              Radius.circular(6),
                            ),
                          ),
                          height: constraints.maxHeight * .65,
                          child: const Center(
                            child: Text("Hello Hello"),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          );
        },
      ),

enter image description here

It will still show blank space while using MyClipper while heigt<400(around)

Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56
  • why don't you simply use `OutlinedBorder`? – pskink May 12 '22 at 18:24
  • @Yeasin Sheikh not working for different screen sizes – Tech Nerd May 12 '22 at 19:34
  • @TechNerd you can use `LayoutBuilder ` and use its `constraints` to make responsive. – Md. Yeasin Sheikh May 13 '22 at 09:40
  • @pskink I am trying as you said using `OutlinedBorder`. But I think I am missing something and failed to get this result. – Md. Yeasin Sheikh May 13 '22 at 09:48
  • on `getInnerPath` should I return super `getInnerPath`? I am getting confused with `getInnerPath` uses cases. btw gist is great with small rotate issue . – Md. Yeasin Sheikh May 23 '22 at 06:26
  • you cannot return `super.getInnerPath()` as it is not defined - `ShapeBorder` is abstract, as far as i know `getInnerPath` is only used [here](https://github.com/flutter/flutter/blob/fb57da5f945d02ef4f98dfd9409a72b7cce74268/packages/flutter/lib/src/painting/shape_decoration.dart#L346) so it really does not matter what you return from there (unless you use `ShapeDecoration.image`) - btw i forgot about very interesting "feature" of `ShapeBorder` - shape "morphing" - check `ShapeBorder.lerpFrom` and `ShapeBorder.lerpTo` methods – pskink May 24 '22 at 03:43
  • I will a recheck it. and the issue was when rotate clockwise and then rotate back(anti-clockwise) UI suddenly change at around Align(-1,0) – Md. Yeasin Sheikh May 24 '22 at 04:23
  • 1
    just for fun i implemented some shape morphing, click any digit and see how dialpad's shape changes (the magic is in lines #186-#191): https://gist.github.com/pskink/50554a116698f03a862a356c38b75eb3 – pskink May 25 '22 at 09:29
-1

You can use the CustomPainter class. There, you can specify strokeWidth and Color, and then make sure you give it the same path as your above curve.

Miro
  • 364
  • 1
  • 12