Flutter는 강력한 UI 프레임워크로, 기본 위젯 외에도 개발자가 직접 캔버스에 그림을 그릴 수 있는 기능을 제공합니다. 이를 가능하게 하는 것이 Custom Painter입니다. Custom Painter는 복잡한 그래픽, 사용자 정의 애니메이션, 데이터 시각화(그래프, 차트 등)와 같은 고급 UI를 구현할 때 유용하게 사용됩니다. 이번 글에서는 Flutter의 Custom Painter를 사용하는 방법과 주요 개념, 그리고 간단한 예제를 소개하겠습니다.
1. Custom Painter란?
Custom Painter는 Flutter의 Canvas와 Paint 클래스를 사용하여 화면에 원하는 도형, 그래프, 텍스트 등을 그릴 수 있도록 도와주는 기능입니다. 이를 통해 기본 제공 위젯만으로는 구현하기 어려운 사용자 정의 UI를 만들 수 있습니다.
CustomPainter 클래스는 두 가지 주요 메서드를 제공합니다:
- paint(Canvas canvas, Size size): 캔버스에 그릴 내용을 정의합니다.
- shouldRepaint(covariant CustomPainter oldDelegate): UI를 다시 그릴 필요가 있는지 여부를 결정합니다.
2. Custom Painter 기본 구조
Custom Painter를 사용하려면 다음과 같은 기본 구조를 따라야 합니다:
- CustomPainter를 상속받은 클래스를 생성합니다.
- paint 메서드에서 그림을 그립니다.
- CustomPaint 위젯에서 CustomPainter를 사용하여 UI에 추가합니다.
기본 코드 예제
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: Text('Custom Painter Example')),
body: Center(
child: CustomPaint(
size: Size(300, 300),
painter: MyPainter(),
),
),
),
);
}
}
class MyPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// Paint 설정
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
// 원 그리기
canvas.drawCircle(
Offset(size.width / 2, size.height / 2), // 중심 좌표
100, // 반지름
paint, // 페인트 스타일
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false; // 다시 그릴 필요가 없으면 false 반환
}
}
주요 구성 요소:
- CustomPainter: 그림을 그릴 클래스를 정의합니다.
- paint 메서드: 캔버스와 페인트를 사용하여 도형을 그립니다.
- CustomPaint: Flutter 위젯 트리에 CustomPainter를 삽입하는 위젯입니다.
3. Custom Painter로 다양한 도형 그리기
3.1 선(Line) 그리기
선은 canvas.drawLine 메서드를 사용하여 그릴 수 있습니다.
class LinePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.red
..strokeWidth = 4;
canvas.drawLine(
Offset(0, 0), // 시작점
Offset(size.width, size.height), // 끝점
paint,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
3.2 사각형(Rectangle) 그리기
사각형은 Rect 객체와 함께 canvas.drawRect를 사용하여 그립니다.
class RectanglePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.green
..style = PaintingStyle.fill;
final rect = Rect.fromLTWH(50, 50, 200, 100); // x, y, width, height
canvas.drawRect(rect, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
3.3 곡선(Path) 그리기
Path 객체를 사용하면 복잡한 곡선을 그릴 수 있습니다.
class CurvePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.purple
..style = PaintingStyle.stroke
..strokeWidth = 3;
final path = Path()
..moveTo(0, size.height / 2) // 시작점
..quadraticBezierTo(
size.width / 2, 0, // 곡선의 제어점
size.width, size.height / 2, // 끝점
);
canvas.drawPath(path, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
3.4 텍스트 그리기
TextPainter 클래스를 사용하여 캔버스에 텍스트를 그릴 수 있습니다.
class TextPainterExample extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final textStyle = TextStyle(
color: Colors.black,
fontSize: 24,
);
final textSpan = TextSpan(
text: 'Hello, Flutter!',
style: textStyle,
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout(
minWidth: 0,
maxWidth: size.width,
);
final offset = Offset(size.width / 2 - textPainter.width / 2, size.height / 2 - textPainter.height / 2);
textPainter.paint(canvas, offset);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
4. Custom Painter와 애니메이션
Custom Painter를 애니메이션과 결합하면 동적인 그래픽을 만들 수 있습니다. 이를 위해 AnimationController와 CustomPainter를 함께 사용합니다.
애니메이션 예제: 원의 크기 변화
class AnimatedCircle extends StatefulWidget {
@override
_AnimatedCircleState createState() => _AnimatedCircleState();
}
class _AnimatedCircleState extends State<AnimatedCircle>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
)..repeat(reverse: true);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return CustomPaint(
size: Size(300, 300),
painter: CirclePainter(_controller.value),
);
},
);
}
}
class CirclePainter extends CustomPainter {
final double progress;
CirclePainter(this.progress);
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
final radius = 50 + progress * 100;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2),
radius,
paint,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true; // 애니메이션 값에 따라 계속 다시 그리기
}
}
- AnimationController: 애니메이션을 관리합니다.
- AnimatedBuilder: 애니메이션 값에 따라 CustomPaint를 다시 렌더링합니다.
- progress: 애니메이션 값(0.0에서 1.0)을 기반으로 동적으로 원의 크기를 변경합니다.
5. Custom Painter의 활용 사례
Custom Painter는 다음과 같은 상황에서 유용하게 사용됩니다:
- 차트 및 그래프 시각화:
- 막대 차트, 라인 차트, 파이 차트 등.
- 사용자 정의 애니메이션:
- 물결, 스플래시 효과, 로딩 애니메이션 등.
- 데이터 시각화:
- 데이터를 캔버스에 표현하는 대시보드와 같은 UI.
- 복잡한 커스텀 UI:
- 앱의 특수한 디자인 요구사항에 맞춘 커스텀 UI 요소.
결론
Flutter의 Custom Painter는 캔버스 기반의 그래픽을 생성하고 복잡한 UI를 구현할 수 있는 강력한 도구입니다. 기본적인 도형 그리기부터 애니메이션 효과까지 다양한 기능을 제공하며, 이를 통해 앱의 디자인을 한층 더 독창적으로 만들 수 있습니다. 이번 글에서 소개한 예제를 바탕으로 Custom Painter를 활용한 고급 UI를 구현해보세요!
'Flutter' 카테고리의 다른 글
Flutter에서 반응형 그리드 레이아웃 구현하기 (0) | 2025.03.23 |
---|---|
Flutter에서 그림자(Shadow) 효과 적용하기 (0) | 2025.03.23 |
Flutter에서 이미지 오버레이(Image Overlay) 만들기 (0) | 2025.03.22 |
Flutter에서 원형 이미지(Circular Image) 만들기 (0) | 2025.03.20 |
Flutter에서 그라디언트 버튼(Gradient Button) 만들기 (0) | 2025.03.20 |