Rahul Devanavar
Rahul Devanavar

Reputation: 4165

How to use ClipPath Flutter

I want to give the above background for container, tried the following code.but it's not working

ClipPath(
            clipper: TriangleClipper(),
            child: Container(
                margin: EdgeInsets.only(top: 20, right: 20),
                padding: EdgeInsets.all(20),
                decoration: BoxDecoration(
                    color: cardBackground,
                    borderRadius: BorderRadius.circular(10))),


    Class TriangleClipper extends CustomClipper<Path> {
      @override
      Path getClip(Size size) {
        final path = Path();
        path.lineTo(0.0, size.height);
        path.lineTo(size.width, size.height);
        path.close();
        return path;
      }
    
      @override
      bool shouldReclip(TriangleClipper oldClipper) => false;
    }

Upvotes: 3

Views: 2646

Answers (2)

Jigar Patel
Jigar Patel

Reputation: 5423

With ClipPath, you need to draw the entire path which you want to carve, which will include drawing the triangle as well as the top-left and top-right rounded corners, because the corresponding original corners (borderRadius: BorderRadius.circular(10)) will be cropped out. One way you can do this is something like this.

class _MyWidgetState extends State<MyWidget> {

  @override
  Widget build(BuildContext context) {
    return ClipPath(
      clipper: TriangleClipper(),
      child: Container(
        padding: EdgeInsets.fromLTRB(20, 30, 20, 20),   //extra 10 for top padding because triangle's height = 10
        decoration: BoxDecoration(
          color: Colors.green,
          borderRadius: BorderRadius.circular(10),
        ),
        child: Text('My parent is a fancy container'),
      ),
    );
  }
}


class TriangleClipper extends CustomClipper<Path> {
  
  double radius = 10, tw = 20, th = 10;      //tw & th = triangle width & height
  
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(0, size.height);
    path.lineTo(size.width, size.height);
    path.lineTo(size.width, th + radius);
    path.arcToPoint(Offset(size.width - radius, th), radius: Radius.circular(radius), clockwise: false);
    path.lineTo(radius + 10 + tw, th);
    path.lineTo(radius + 10 + tw/2, 0);      //in these lines, the 10 is to have a space of 10 between the top-left corner curve and the triangle
    path.lineTo(radius + 10, th);
    path.lineTo(radius, th);
    path.arcToPoint(Offset(0, th + radius), radius: Radius.circular(radius), clockwise: false);
    return path;
  }

  @override
  bool shouldReclip(TriangleClipper oldClipper) => false;
}

Result:

enter image description here

Upvotes: 3

Kherel
Kherel

Reputation: 16185

It's better to use custom shapes for this kind of purposes..

enter image description here

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(18.0),
            child: Container(
              decoration: ShapeDecoration(
                color: Color(0xFFf3effd),
                shape: MyBorderShape(),
                shadows: [
                  BoxShadow(
                      color: Colors.black38,
                      blurRadius: 8.0,
                      offset: Offset(1, 1)),
                ],
              ),
              height: 100,
            ),
          ),
        ),
      ),
    );
  }
}

class MyBorderShape extends ShapeBorder {
  @override
  EdgeInsetsGeometry get dimensions => EdgeInsets.zero;

  @override
  Path getInnerPath(Rect rect, {TextDirection textDirection}) => null;

  final double holeSize = 70;
  final double borderRadius = 10;

  @override
  Path getOuterPath(Rect rect, {TextDirection textDirection}) {
    print(rect.topLeft);
    var startX = rect.topLeft.dx;
    var startY = rect.topLeft.dy;

    return Path.combine(
      PathOperation.union,
      Path()
        ..addRRect(RRect.fromRectAndRadius(rect, Radius.circular(borderRadius)))
        ..close(),
      Path()
        ..moveTo(startX + 20, startY)
        ..lineTo(startX + 35, startY - 15)
        ..lineTo(startX + 50, startY)
        ..close(),
    );
  }

  @override
  void paint(Canvas canvas, Rect rect, {TextDirection textDirection}) {}

  @override
  ShapeBorder scale(double t) => this;
}

Upvotes: 2

Related Questions