Search code examples
fluttercontainersborder

Flutter - How can I add a border to vertical BorderRadius in Container?


I want to achieve the effect in the image below. I want to add a border only to the top of a Container that has a borderradius with a radialgradient inside. How can I do that? Looks like:

I tried this way:

Column(
  children: [
    const SizedBox(
      height: 300,
    ),
    Container(
      height: 400,
      width: double.infinity,
      decoration: const BoxDecoration(
        // The border in this section has no effect. How can I get it to be like in the picture?
        border: Border(
          top: BorderSide(color: Color(0XFFD9ECA7), width: 9.0),
        ),
        borderRadius: BorderRadius.vertical(
          top: Radius.elliptical(180, 90),
        ),
        gradient: RadialGradient(
          colors: [Color(0xFF730202), Color(0XFF6D7DC9)],
          center: Alignment(0.0, 1.9),
          radius: 1.9,
          stops: <double>[0.0, 0.9],
        ),
      ),
    ),
  ],
);

Solution

  • You can achieve the desired result by using CustomPainter and CustomClipper.

    Stack(
      children: [
        Container(
          color: const Color(0xFF191717),
          width: double.infinity,
          height: 300,
        ),
        ClipPath(
          clipper: CustomShape(),
          child: Container(
            height: 400,
            width: double.infinity,
            decoration: const BoxDecoration(
              gradient: RadialGradient(
                colors: [Color(0xFF730202), Color(0XFF6D7DC9)],
                center: Alignment(0.0, 1.9),
                radius: 1.9,
                stops: <double>[0.0, 0.9],
              ),
            ),
          ),
        ),
        CustomPaint(
          painter: CustomBorder(),
          child: Container(
            height: 400,
          ),
        ),
      ],
    );
    

    CustomShape:

      class CustomShape extends CustomClipper<Path> {
      @override
      getClip(Size size) {
        var path = Path();
        path.lineTo(0, size.height - 50);
        path.quadraticBezierTo(
            size.width / 2, size.height, size.width, size.height - 50);
        path.lineTo(size.width, 0);
        path.close();
    
        return path;
      }
    
      @override
      bool shouldReclip(CustomClipper oldClipper) {
        return true;
      }
    }
    

    CustomBorder:

      class CustomBorder extends CustomPainter {
      @override
      void paint(Canvas canvas, Size size) {
        var paint = Paint();
        paint.color = const Color(0XFFD9ECA7);
        paint.style = PaintingStyle.stroke;
        paint.strokeWidth = 9;
    
        var path = Path();
    
        path.moveTo(0, size.height - 50);
        path.quadraticBezierTo(
            size.width / 2, size.height, size.width, size.height - 50);
        path.moveTo(size.width, 0);
        path.close();
        canvas.drawPath(path, paint);
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) {
        return true;
      }
    }