플러터 CustomPaint 사용법 | CustomPaint 물결 그리기 예제 | Flutter

2022. 7. 14. 17:00앱개발/플러터 사용법

플러터 CustomPaint 의 사용법 및 예제

 

목차

1. CustomPaint의 필요성

2. CustomPaint 사용법

3. CustomPaint 이용해 기본 모양 그려보기

1️⃣ 직선 그리기

2️⃣ 원 그리기

4. CustomPaint 이용해 응용된 모양 그리기

3️⃣ 물결 그리기

 

 

#  CustomPaint의 필요성

 

CustomPaint class는 클래스의 이름에서 알수있듯 커스텀한 나만의 위젯을 화면에 그려주는 위젯이다. 즉 아름다운 UI를 디자인하고자 할 때 꼭 필요한 클래스다.

물론 기존의 decoration을 이용해 위젯의 모양을 설정해 줄 수도있다. 예를 들어 위젯을 둥글게 한다든가 모서리를 둥글게 만든다 던가 하는 것 처럼 말이다. 하지만 decoration 속성으로는 복잡한 모양의 위젯을 디자인 하기 어려울 수 있다.

디자인  CustomPaint를 사용하지 않고 디자인한 파일을 플러터로 바로 가져와서 사용할 수도 있다. 하지만 파일의 용량이 너무 크거나 혹은 지원하지 않는 파일 형식일 경우 플러터에서 디자인 파일을 바로 사용할 수 없는 경우가 있을 수 있다. 그렇기 때문에 CustomPaint 위젯이 꼭 필요하다.

CustomPaint의 사용법을 알아보고 기본 모양을 그려보며 위젯의 사용법을 익혀보자.

 

 

 

#  CustomPaint 사용법

 

CustomPaint는 캔버스를 만들고 그 위에 그림을 그리는 플러터 위젯이다.

CustomPaint(
    size : Size(300, 200), // child가 없다면 size속성은 null이 아니어야 한다.
    painter : LinePainter()
)

 

먼저, CustomPaint는 자기 안에 정의되어있는 painter 메소드에게 캔버스에 그릴 것을 요청한다. child 프로퍼티로 넘긴 위젯을 그리면 위젯이 foregroundPainter 프로퍼티가 그릴 것을 요청한다. painter들은 시작점에서 시작해 특정 사이즈의 지역을 아우르는 직사각형 범위로 한정되어있다. 만약 painter들이 할당된 영역을 벗어나면 이미지를 보여주기에 메모리가 부족하게 될것이다.

더보기

프로퍼티

 

CustomPaint는 반드시 2개의 프로퍼티를 가져야한다.

1. painter : children 전에 그려짐

2. size : 라인이 그려질 캔버스 정의

 

만약 컨테이너, 스택, 행, 열과 같은 위젯 위에 그리고 싶다면 아래와 같이 size 프로퍼티는 child로  painter 프로퍼티는 foregroundPainter로 대체하여 사용하면 된다. ( 대체 : size -> child , painter -> foregroundPainter)

CutstomPaint(
    child: Container(
    	width : 300,
        height : 300,
        color: Colors.orangeAccent,
    ),
    forgroundPainter: LinePainter(),
)

위 코드처럼 child의 값이 꼭 Container가 아니어도 된다. foregroundPainterchild 위에 그릴 것을 정하는 값이다.

 

 

 

#  CustomPaint 이용해 기본 모양 그려보기

 

다음은 CustomPaint를 이용해 직선과 원 2개의 기본 도형을 그려보는 예제이다.

 

1️⃣ 직선 그리기

 

본격적으로 CustomPaint를 활용하기 이전에 가장 간단한 라인 하나를 그려보자. CustomPaint를 이용해서 라인 한 줄을 그리는 코드는 다음과 같다.

 

CutstomPaint(
    child: Container(
    	width : 300,
        height : 300,
        color: Colors.orangeAccent,
    ),
    forgroundPainter: LinePainter(),
)

 

 

자 이제 LinePainter 클래스를 작성해보자. 이 클래스는 CustomPainter를 상속한다. LinePainter은 실제 그림을 그려주는 클래스라고 생각하면 된다. paintcanvas 메소드를 가지고 있는데 이 두 메소드가 선, 원, 직사각형 또는 다양한 모양을 그릴 수 있게 해준다.

class LinePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint() // 초기화
        ..color = Colors.indigoAccent
        ..strokeWidth = 15;

    Offset start = Offset( size.width/4 , size.height/2 ); // 선의 시작점
    Offset end = Offset( size.width/4*3, size.height/2 ); // 선의 끝점

    canvas.drawLine(start, end, paint); // drawLine 메소드 이용해서 선 그림
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

 

위 코드의 4번째 줄의 Paint 클래스는 프로퍼티를 초기화 시키는 기능을 수행한다. 우리가 도화지에 그림 그리기 전 무슨 펜으로 그릴지 정하는 것 처럼 화면에 그림 그릴 땐 Paint 클래스가 그림 그리기 전 무슨 펜을 사용할 지 정하는 역할을 한다고 생각하면 된다.

 

위 코드의 3번째 줄과 11번째 줄의 Canvas 클래스에 대해 알아보자. Canvas 클래스는 그림 그리기 위한 다양한 도구를 제공해주는 클래스라고 생각하면 된다. 직선을 그리는 메소드, 원을 그리는 메소드 등 아주 다양한 도구를 제공하고있다.

 

결과 화면

 

 

2️⃣ 원 그리기

 

CustomPaint를 사용하면 원도 아주 쉽게 그릴 수 있다. Canvas 클래스가 제공하는 drawCircle 메소드를 이용해서 화면에 원을 그려보자. 첫 번째 매개변수로는 원을 어떻게 정렬할지에 대한 값을 넘기고 두 번째 매개변수로는 원의 반지름을 어떻게 정할지에 대한 값을 넘긴다.

위에서 작성한 LinePainter를 약간 변형해서 CirclePainter를 작성해보면 다음과 같다.

class CirclePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()
      ..color = Colors.indigoAccent
      ..strokeWidth = 15;

    Offset center = Offset( size.width/2, size.height/2 );

    canvas.drawCircle(center, 100 , paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

 

결과 화면

 

 

#  CustomPaint 이용해 응용된 모양 그리기

 

이제 여러 번의 곡선이 존재하는 복잡한 모양을 그려보자.

 

3️⃣ 물결 무늬 그리기

 

이번엔 화면에 물결 무늬를 그려보자. Canvas 클래스는 drawPath 라는 메소드를 제공해준다. drawPath는 선의 경로를 결정해준다. Path 클래스는 좌표를 이동시키기에 매우 유용한 클래스다. 곡선을 그리기 위해선 path.quadraticBezierTo(x1, y1, x2, y2) 메소드를 이용하는데 x1, y1는 컨트롤 포인트고 x2, y2는 목적지다. 즉 점(x1 , y1)를 제어점으로 가지면서 출발지부터 목적지인 점(x2, y2)까지 곡선을 그린다는 말이다. 

class CurvedPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    var paint = Paint()
        ..color = Colors.indigoAccent
        ..strokeWidth = 15;

    var path = Path();
    path.moveTo(0, size.height * 0.5); // 시작점
    path.quadraticBezierTo( // 모서리를 둥글게 말기 위한 메소드
        size.width * 0.25,
        size.height * 0.5,
        size.width * 0.5,
        size.height * 0.75 );
    path.quadraticBezierTo(
        size.width * 0.75,
        size.height * 0.97,
        size.width * 1.0,
        size.height * 0.8 );
    path.lineTo(size.width, size.height); // 오른쪽 위에서 오른쪽 아래 라인
    path.lineTo(0, size.height); // 왼쪽 위에서 왼쪽 아래 라인

    canvas.drawPath(path, paint);

  }

 

결과 화면

이 예제에서 어려운 점은 도형을 컨트롤 포인트를 어떻게 설정할지 정하는 것이다.. 이 예제는 간단한 곡선이라 문제가 없지만 복잡한 곡선을 그리는 예제일 경우 적당한 컨트롤 포인트를 잡는 것이 까다롭고 또 결정하기에 시간이 많이 들 수 있다.