跳到主要内容

เนื้อหาภาษาไทย / 泰语内容

系统指南 内容已审核

การสร้าง Custom Painter ใน Flutter

บทความนี้แนะนำ `CustomPainter` ใน Flutter ซึ่งเป็นเครื่องมือที่ช่วยให้นักพัฒนาสามารถวาด UI ที่กำหนดเองได้โดยตรงบน Canvas โดยใช้ส่วนประกอบหลักคือ Canvas, Paint แ...

การสร้าง Custom Painter ใน Flutter: ปลดปล่อยพลังแห่งการวาด

ในโลกของการพัฒนาแอปพลิเคชัน Flutter ที่เต็มไปด้วย Widget สำเร็จรูปมากมาย บางครั้งเราก็ต้องการสร้าง UI ที่มีความเฉพาะเจาะจงและซับซ้อนเกินกว่าที่ Widget เหล่านั้นจะทำได้ นี่คือจุดที่ CustomPainter เข้ามามีบทบาทสำคัญ ช่วยให้เราสามารถวาดภาพที่กำหนดเองลงบน Canvas ได้อย่างอิสระ บทความนี้จะพาคุณไปรู้จักกับ Custom Painter และเรียนรู้วิธีการใช้งาน Canvas, Paint และ Path เพื่อสร้างสรรค์ภาพวาดที่น่าทึ่ง

CustomPainter คืออะไร?

CustomPainter คือ Class ใน Flutter ที่ช่วยให้เราสามารถควบคุมการวาดภาพบน Canvas ได้อย่างเต็มที่ Canvas เปรียบเสมือนผืนผ้าใบดิจิทัลที่เราสามารถวาดเส้น รูปร่าง ข้อความ และอื่นๆ ลงไปได้ CustomPainter จะถูกใช้ร่วมกับ Widget CustomPaint เพื่อแสดงผลภาพวาดที่เราสร้างขึ้น

ส่วนประกอบสำคัญ: Canvas, Paint และ Path

ก่อนที่จะเริ่มลงมือเขียนโค้ด เรามาทำความเข้าใจส่วนประกอบหลักที่เกี่ยวข้องกับการสร้าง Custom Painter กันก่อน:

  • Canvas: คือพื้นผิวที่เราจะทำการวาดภาพลงไป Canvas มี methods มากมายสำหรับการวาดรูปทรงต่างๆ เช่น เส้น วงกลม สี่เหลี่ยม หรือแม้กระทั่งรูปภาพ
  • Paint: คือเครื่องมือที่เราใช้ในการกำหนดลักษณะของภาพวาด เช่น สี ขนาด ความหนาของเส้น รูปแบบการเติมสี (fill) หรือขอบ (stroke)
  • Path: คือลำดับของเส้นตรงและเส้นโค้งที่เชื่อมต่อกัน Path ถูกใช้เพื่อสร้างรูปทรงที่ซับซ้อนและไม่สามารถสร้างได้ด้วย methods การวาดรูปทรงพื้นฐานของ Canvas

ขั้นตอนการสร้าง Custom Painter

ต่อไปนี้เป็นขั้นตอนการสร้าง Custom Painter อย่างละเอียด:

  1. สร้าง Class ที่ extends CustomPainter: สร้าง Class ใหม่และ extends จาก CustomPainter
  2. Override method paint: Implement method paint(Canvas canvas, Size size) ซึ่งเป็น method ที่ใช้ในการวาดภาพลงบน Canvas canvas คือ object ของ Canvas ที่เราจะใช้ในการวาด และ size คือขนาดของ Widget ที่ CustomPainter ถูกใช้งาน
  3. Override method shouldRepaint: Implement method shouldRepaint(covariant CustomPainter oldDelegate) Method นี้จะถูกเรียกเมื่อ Widget ถูก rebuild และใช้เพื่อตัดสินใจว่าควรจะวาดภาพใหม่หรือไม่ โดยปกติแล้วเราจะเปรียบเทียบ properties ของ oldDelegate (CustomPainter ก่อนหน้า) กับ properties ของ CustomPainter ปัจจุบัน หาก properties แตกต่างกัน แสดงว่าเราจำเป็นต้องวาดภาพใหม่

ตัวอย่าง: วาดวงกลม

มาลองสร้าง Custom Painter อย่างง่ายเพื่อวาดวงกลม:

import 'package:flutter/material.dart';

class CirclePainter extends CustomPainter {
  final Color color;
  final double radius;

  CirclePainter({required this.color, required this.radius});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..style = PaintingStyle.fill; // หรือ PaintingStyle.stroke

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

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

  @override
  bool shouldRepaint(covariant CirclePainter oldDelegate) {
    return color != oldDelegate.color || radius != oldDelegate.radius;
  }
}

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: CirclePainter(color: Colors.blue, radius: 50),
      child: Container(), // สามารถใส่ child widget อื่นๆ ได้
    );
  }
}

คำอธิบายโค้ด:

  • CirclePainter เป็น Class ที่ extends จาก CustomPainter
  • Constructor รับค่า color และ radius เพื่อกำหนดสีและขนาดของวงกลม
  • ใน method paint เราสร้าง Paint object และกำหนดสีและ style ให้กับ paint
  • canvas.drawCircle ใช้ในการวาดวงกลม โดยรับค่า center, radius และ paint
  • shouldRepaint จะ return true หากสีหรือรัศมีของวงกลมมีการเปลี่ยนแปลง
  • MyWidget ใช้ CustomPaint widget และส่ง CirclePainter เป็น painter

ตัวอย่าง: วาดเส้น

มาลองสร้าง Custom Painter เพื่อวาดเส้น:

import 'package:flutter/material.dart';

class LinePainter extends CustomPainter {
  final Color color;
  final double strokeWidth;

  LinePainter({required this.color, required this.strokeWidth});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke;

    final startPoint = Offset(0, size.height / 2);
    final endPoint = Offset(size.width, size.height / 2);

    canvas.drawLine(startPoint, endPoint, paint);
  }

  @override
  bool shouldRepaint(covariant LinePainter oldDelegate) {
    return color != oldDelegate.color || strokeWidth != oldDelegate.strokeWidth;
  }
}

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: LinePainter(color: Colors.red, strokeWidth: 5),
      child: Container(),
    );
  }
}

คำอธิบายโค้ด:

  • LinePainter เป็น Class ที่ extends จาก CustomPainter
  • Constructor รับค่า color และ strokeWidth เพื่อกำหนดสีและความหนาของเส้น
  • ใน method paint เราสร้าง Paint object และกำหนดสี ความหนา และ style ให้กับ paint
  • canvas.drawLine ใช้ในการวาดเส้น โดยรับค่า startPoint, endPoint และ paint
  • shouldRepaint จะ return true หากสีหรือความหนาของเส้นมีการเปลี่ยนแปลง
  • MyWidget ใช้ CustomPaint widget และส่ง LinePainter เป็น painter

การใช้งาน Path

Path ช่วยให้เราสามารถสร้างรูปทรงที่ซับซ้อนได้ มาลองสร้าง Custom Painter ที่วาดรูปสามเหลี่ยมโดยใช้ Path:

import 'package:flutter/material.dart';

class TrianglePainter extends CustomPainter {
  final Color color;

  TrianglePainter({required this.color});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..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(); // ปิด Path เพื่อสร้างรูปทรงที่สมบูรณ์

    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(covariant TrianglePainter oldDelegate) {
    return color != oldDelegate.color;
  }
}

class MyWidget extends StatelessWidget {
  const MyWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: TrianglePainter(color: Colors.green),
      child: Container(),
    );
  }
}

คำอธิบายโค้ด:

  • TrianglePainter เป็น Class ที่ extends จาก CustomPainter
  • Constructor รับค่า color เพื่อกำหนดสีของสามเหลี่ยม
  • ใน method paint เราสร้าง Paint object และกำหนดสีและ style ให้กับ paint
  • เราสร้าง Path object และใช้ method moveTo และ lineTo เพื่อกำหนดจุดต่างๆ ของสามเหลี่ยม
  • path.close() ใช้เพื่อปิด Path และสร้างรูปทรงสามเหลี่ยมที่สมบูรณ์
  • canvas.drawPath ใช้ในการวาด Path โดยรับค่า path และ paint
  • shouldRepaint จะ return true หากสีของสามเหลี่ยมมีการเปลี่ยนแปลง
  • MyWidget ใช้ CustomPaint widget และส่ง TrianglePainter เป็น painter

กรณีใช้งานจริงและข้อผิดพลาดที่พบบ่อย

  • การสร้าง Custom Chart: Custom Painter สามารถใช้ในการสร้าง chart ที่มีความซับซ้อน เช่น Bar Chart, Line Chart หรือ Pie Chart
  • การสร้าง Loading Indicator: Custom Painter สามารถใช้ในการสร้าง Loading Indicator ที่มีเอกลักษณ์เฉพาะตัว
  • ข้อผิดพลาด: การลืม Override method shouldRepaint อาจทำให้ Widget ไม่ rebuild เมื่อข้อมูลมีการเปลี่ยนแปลง
  • ข้อผิดพลาด: การไม่ปิด Path (path.close()) อาจทำให้รูปทรงที่วาดไม่สมบูรณ์
  • ข้อผิดพลาด: การใช้ Paint object เดียวกันสำหรับหลายๆ การวาด อาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิด ควรสร้าง Paint object ใหม่สำหรับแต่ละการวาดหากต้องการลักษณะที่แตกต่างกัน

สรุป

CustomPainter เป็นเครื่องมือที่มีประสิทธิภาพในการสร้าง UI ที่มีความซับซ้อนและเฉพาะเจาะจงใน Flutter ด้วยการใช้งาน Canvas, Paint และ Path อย่างเหมาะสม เราสามารถสร้างสรรค์ภาพวาดที่น่าทึ่งและเพิ่มความน่าสนใจให้กับแอปพลิเคชันของเราได้ หวังว่าบทความนี้จะเป็นประโยชน์และช่วยให้คุณเริ่มต้นใช้งาน Custom Painter ได้อย่างมั่นใจ ในบทความถัดไป เราจะไปเรียนรู้เกี่ยวกับการใช้ Slivers เพื่อสร้าง Scrollable Layouts ที่ซับซ้อนยิ่งขึ้น

Office.in.th Custom Service

想基于此结构开发或定制系统?

Office.in.th 承接企业级 Web Application、API Integration 以及政府/企业管理系统的设计与开发,并提供长期支持。

查看软件开发服务