ClipPath class
경로를 사용하여 자식을 클리핑 하는 위젯입니다.
위젯을 그릴 때마다 델리게이트에 대한 콜백을 호출합니다. 콜백은 경로를 반환하고, 위젯은 자식 위젯이 경로 외부에 그려지는 것을 방지합니다.
경로에 클리핑 하는 것은 비용이 많이 듭니다. 특정 도형에는 더 최적화된 위젯이 있습니다.
- 사각형으로 잘라내려면 ClipRect 를 사용하세요.
- 타원이나 원형으로 잘라내려면 ClipOval을 사용해보세요.
- 둥근 사각형으로 잘라내려면 ClipRRect 를 사용해보세요.
예제 코드
컨테이너를 사용하면서 삼각형을 만들고 싶었던 적이 있는가? 당연하겠지만 컨테이너를 삼각형 모양으로 만들어주는 편리한 위젯은 아직까지는(2025.06.30) 없기 때문에 삼각형 모양의 컨테이너를 만들고 싶다면 직접 커스텀으로 만들어야 한다. 근데 여기서 이제 흔히들 아는 위젯이 있다. 바로 CustomPaint 위젯인데 이 위젯은 말 그대로 직접 화면에다가 그리는 동작을 한다. 즉 내가 원하는 "컨테이너를 삼각형으로 만들고 싶다" 와는 구조상으로 다르다는 것이다. 이럴 때 주어진 컨테이너에서 보이는 영역을 자를 수 있게 만들어주는 위젯이 있는데 바로 ClipPath이다.
이 ClipPath 위젯은 자식 위젯(child)의 모양을 커스텀한 경로(path)를 기준으로 자르는 데 사용된다. 예를 들어 원형, 삼각형, 또는 자유로운 곡선 모양으로 위젯을 클리핑 할 수 있다. 바로 알아보자.
하위 속성
| 속성명 | 타입 | 기본값 | 설명 |
| child | Widget? | – | 잘라낼 대상이 되는 자식 위젯 |
| clipper | CustomClipper<Path>? | null | 자르기 경로를 정의하는 클리퍼 객체 |
| clipBehavior | Clip | Clip.antiAlias | 잘라낸 테두리를 어떻게 처리할지 결정하는 방식 |
먼저 ClipPath 위젯을 적용하면 내가 원하는 상자 모양을 만들 수가 있다.
ClipPath(
child: Container(),
clipper: MyCustomClipper(),
)
여기서 ClipPath 의 기본 속성은 CustomClipper 인데 이는 방향을 정해주는 역할을 해준다.
CustomClipper<Path> 위젯을 확장하면 방향을 정의할 수 있게 된다.
class MyCustomClipper extends CustomClipper<Path> {}
이렇게 class 를 생성하게 되면 @override 된 부분이 두 개 만들어질 것이다.
여기서 getClip은 새로운 방향이 구축되는 부분인데 별 모양이든, 곡선 형태이든 랜덤 방식으로도 설정할 수 있다.
@override
Path getClip(Size size) {
Path path = Path();
// TODO 자를 모양 만들기
return path;
}
또한 shouldReclip 도 마찬가지로 오버라이드 해야 하지만 이건 간단히 false 를 반환하게 시켜주면 된다.
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
그렇다면 당연하게도 "어떻게 자르는지" 알아보자.
앞서 말했듯이 getClip 안에서 만들어주면 된다.
솔직히 CustomPaint 를 사용해 봤다면 겁나 친근하게 느껴질 것인데 위의 코드에서 Path 타입 path 변수를 하나 만들어 놨다. 이거 가지고 만들어주면 된다.
먼저 삼각형을 그려볼 것이니 첫 번째 꼭짓점, 위쪽 중앙에 위치해 있는 것을 그려줘야 한다.
@override
Path getClip(Size size) {
Path path = Path();
path.moveTo(size.width / 2, 0); // 전체 너비의 절반 위치 (가로 중앙)에서 y=0 위치로 이동
return path;
}
아직까지는 아무것도 그리지 않았으니 당연히 아무것도 화면에 표시되지 않는다.
다음은 두 번째 꼭짓점을 왼쪽 아래에 그려줄 것이다.
@override
Path getClip(Size size) {
Path path = Path();
path.moveTo(size.width / 2, 0);
path.lineTo(0, size.height); // x=0 (왼쪽 끝), y=size.height (아래 끝)
return path;
}
마찬가지로 아직 화면에 나타나지 않는다.
이제 삼각형이니 세 번째 꼭짓점을 그려줘야 할 것이다. 이 꼭짓점은 오른쪽 아래에 그려주면 된다.
자, 이제 이러면 삼각형이 완성되는데 마무리를 해줘야 하니 close 도 추가해 주면 된다.
@override
Path getClip(Size size) {
Path path = Path();
path.moveTo(size.width / 2, 0);
path.lineTo(0, size.height);
path.lineTo(size.width, size.height); // x=size.width (오른쪽 끝), y=size.height (아래 끝)
path.close();
return path;
}

이러면 바로 손쉽게 삼각형을 그릴 수 있다. 하지만 여기서 간단히 CustomPaint 와 ClipPath 를 DevTool 로 비교해 보고 넘어가겠다.
현재 ClipPath 로 제작한 컨테이너의 경우엔

보이는 것처럼 절취선으로 컨테이너가 우리가 만든 기준에 맞게 잘렸다는 것을 알 수 있다.
하지만 CustomPaint 로 만든 삼각형의 경우엔
class MyCustomPaint extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
final path = Path();
path.moveTo(size.width / 2, 0);
path.lineTo(0, size.height);
path.lineTo(size.width, size.height);
path.close();
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}

그냥 이 위젯 자체가 삼각형으로 되어 있는 것을 알 수 있다. 위의 코드를 보면 알겠지만 거의 차이가 없다고 봐도 무방한 제작 방식이다. 그러므로 둘이 사용처의 차별점을 두는 것은 기존 위젯을 유지하되, 거기서 모양에 맞게 잘라내고 싶은지.. 인지 아니면 진짜 처음부터 그 모양의 위젯을 제작하고 싶은지.. 일 것이다.
삼각형만 만들면 조금 심심하니 별 만드는 코드는 가볍게 봐보길 바란다. 각의 개수를 받게 만들어주면 원하는 각을 가진 별을 만들 수 있게 된다.
ClipPath(
clipper: StarClipper(5),
child: Container(
width: 200,
height: 200,
color: Colors.yellow,
),
)
class StarClipper extends CustomClipper<Path> {
final int numberOfPoints;
StarClipper(this.numberOfPoints);
@override
Path getClip(Size size) {
final Path path = Path();
final double halfWidth = size.width / 2;
final double halfHeight = size.height / 2;
final double radius = min(halfWidth, halfHeight);
final double innerRadius = radius / 2.5;
final double angle = pi / numberOfPoints;
for (int i = 0; i < numberOfPoints * 2; i++) {
final double r = (i % 2 == 0) ? radius : innerRadius;
final double x = halfWidth + r * cos(i * angle - pi / 2);
final double y = halfHeight + r * sin(i * angle - pi / 2);
if (i == 0) {
path.moveTo(x, y);
} else {
path.lineTo(x, y);
}
}
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
}

이것 또한 마찬가지로 컨테이너에서 별모양으로 자른 것임을 알 수 있다.
이렇게 간단히 ClipPath 위젯에 대해 알아보았다. 개인적으로는 CustomPaint 보다 조금 더 좋아하는 위젯이기도 해서 많은 사용을 부탁드리는 바이다. 도움이 되었길 바라며 마치겠다.