RenderObject Tree: มันคืออะไร, หลักการเรนเดอร์และบทบาทใน Flutter

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-07-01 เวลาอ่าน: 9 นาที

RenderObject Tree คือระดับที่สามของลำดับชั้นใน Flutter ที่รับผิดชอบการเรนเดอร์อินเทอร์เฟซจริงบนหน้าจอ แต่ละโหนดของทรีนี้ทำการคำนวณขนาด (layout) และการวาด (painting) แปลงค่าคอนฟิกูเรชันของวิดเจ็ตเป็นพิกเซล ต่างจาก Widget Tree ตรงที่ RenderObject Tree ถูกสร้างครั้งเดียวและอัปเดตเฉพาะเมื่อเรขาคณิตหรือลักษณะภายนอกเปลี่ยนแปลง ตาม Flutter API Reference, 2025 ประสิทธิภาพของ RenderObject Tree กำหนดความลื่นไหลของแอนิเมชันและความเร็วในการตอบสนองของแอปพลิเคชันโดยตรง

ประเด็นสำคัญ

  • RenderObject Tree — ลำดับชั้นของออบเจ็กต์การเรนเดอร์ที่คำนวณขนาดและวาดอินเทอร์เฟซบนหน้าจอ
  • แต่ละ RenderObject ทำสองเฟส: layout (การกำหนดขนาดและตำแหน่ง) และ paint (การวาดพิกเซล)
  • RenderObject Tree ถูกสร้างจาก Element Tree และซิงโครไนซ์ผ่านเอลิเมนต์
  • RepaintBoundary แยกส่วนของทรีสำหรับการวาดซ้ำเฉพาะที่โดยไม่กระทบทั้งหน้าจอ
  • ประสิทธิภาพ ของ RenderObject Tree ขึ้นอยู่กับความลึก จำนวนเลเยอร์ และความถี่ในการวาดซ้ำ

RenderObject Tree ใน Flutter คืออะไร?

RenderObject Tree — โครงสร้างลำดับชั้นของออบเจ็กต์การเรนเดอร์ที่เป็นตัวแทนจริงของอินเทอร์เฟซในหน่วยความจำ แต่ละ RenderObject รู้ขนาดของตัวเอง ตำแหน่งบนหน้าจอ และสามารถวาดตัวเองได้ ต่างจากวิดเจ็ตที่มีน้ำหนักเบาและสามารถถูกสร้างใหม่ได้หลายร้อยครั้งต่อวินาที RenderObject เป็นออบเจ็กต์หนักที่มีการเข้าถึงไปป์ไลน์กราฟิกโดยตรง

จากคอนฟิกูเรชันสู่การเรนเดอร์

เส้นทางจากวิดเจ็ตไปยังพิกเซลผ่านสามขั้นตอน: Widget Tree อธิบายสิ่งที่ควรปรากฏบนหน้าจอ; Element Tree จัดการวงจรชีวิต; RenderObject Tree ดำเนินงานจริง แต่ละ RenderObjectWidget (เช่น Padding, Transform, CustomPaint) สร้าง RenderObject ที่ถูกเพิ่มเข้าไปในทรีการเรนเดอร์ RenderBox เป็นประเภท RenderObject ที่พบมากที่สุด ใช้สำหรับ 99% ของวิดเจ็ตมาตรฐาน

สถาปัตยกรรมของ RenderObject

RenderObject — คลาสนามธรรมที่กำหนดอินเทอร์เฟซสำหรับ layout และ paint ประกอบด้วยการอ้างอิงไปยัง RenderObject หลักและออบเจ็กต์ลูก รวมถึงเมธอดนามธรรม: performLayout, paint และ hitTest แต่ละ RenderObject ที่เป็นรูปธรรมนำเมธอดเหล่านี้ไปใช้ตามพฤติกรรมของตนเอง: RenderFlex กระจายพื้นที่ระหว่างเอลิเมนต์ลูก, RenderImage แสดงภาพ, RenderParagraph แสดงข้อความ

dart
abstract class RenderObject {
  RenderObject? parent;
  Constraints constraints;
  ParentData? parentData;
  bool _needsLayout = true;
  bool _needsPaint = true;

  void performLayout();
  void paint(PaintingContext context, Offset offset);
}

ในโครงสร้างอย่างง่ายนี้ RenderObject มีแฟล็ก _needsLayout และ _needsPaint ที่ทำเครื่องหมายออบเจ็กต์ว่าต้องการอัปเดต เมื่อ Widget Tree เปลี่ยนแปลง Element Tree จะทำเครื่องหมาย RenderObject ที่เกี่ยวข้องว่า "สกปรก" สำหรับ layout หรือ paint และในเฟรมถัดไป Flutter จะดำเนินการเฉพาะที่จำเป็นเท่านั้น

สองเฟสของ RenderObject: layout และ paint

แต่ละ RenderObject ดำเนินสองเฟสหลัก: layout (การกำหนดขนาดและตำแหน่ง) และ paint (การวาด) เฟสเหล่านี้ดำเนินการตามลำดับที่เข้มงวด: จัด layout สำหรับทั้งทรีก่อน จากนั้นจึง paint เฟส paint สามารถข้ามได้หาก layout ไม่เปลี่ยนแปลง ซึ่งช่วยประหยัดทรัพยากร GPU

เฟส layout: ข้อจำกัดและขนาด

ระหว่าง layout Flutter ส่ง ข้อจำกัด (constraints) จากบนลงล่างผ่าน RenderObject Tree ผู้ปกครองแต่ละรายกำหนดความกว้างและความสูงต่ำสุดและสูงสุดให้กับออบเจ็กต์ลูก ออบเจ็กต์ลูกคำนวณขนาดของตนเองภายในข้อจำกัดเหล่านี้และส่งคืนให้ผู้ปกครอง กระบวนการนี้เรียกว่า "downward pass" (การส่งข้อจำกัดลง) และ "upward pass" (การส่งขนาดขึ้น)

  • BoxConstraints — ประเภทข้อจำกัดที่พบมากที่สุด: minWidth, maxWidth, minHeight, maxHeight
  • SliverConstraints — ใช้ใน ScrollView สำหรับการทำเวอร์ช่วลไลเซชัน: เพิ่มข้อมูลการเลื่อนไปยังข้อจำกัดมาตรฐาน
  • RenderSliverMultiBoxAdaptor — จัดการ layout ของลิสต์แบบเวอร์ช่วลไลซ์ สร้าง RenderObject เฉพาะสำหรับเอลิเมนต์ที่มองเห็น

เฟส paint: การแสดงผลบนหน้าจอ

หลังจาก layout เสร็จสิ้น Flutter จะดำเนินการ paint — การวาดแต่ละ RenderObject ผู้ปกครองสร้าง PaintingContext ส่งต่อไปยังออบเจ็กต์ลูกและระบุออฟเซ็ต (offset) แต่ละ RenderObject วาดตัวเองบน Canvas โดยใช้พริมิทีฟกราฟิก: สี่เหลี่ยม วงกลม ข้อความ รูปภาพ และการแปลง Canvas โต้ตอบโดยตรงกับ Skia หรือ Impeller

การทำเครื่องหมายโหนดสกปรก

Flutter ใช้กลไก โหนด "สกปรก" เพื่อลดปริมาณงาน เมื่อขนาดของ RenderObject ตัวเดียวเปลี่ยนไป Flutter จะไม่คำนวณ layout ของทั้งทรีใหม่ — มันทำเครื่องหมายโหนดที่เปลี่ยนและบรรพบุรุษที่เป็นไปได้จนถึง RenderBox ที่มีขนาดคงที่ที่ใกล้ที่สุด ในทำนองเดียวกัน เมื่อลักษณะภายนอกเปลี่ยนไป เฉพาะ paint เท่านั้นที่ถูกทำเครื่องหมาย โดยไม่ต้อง layout ซ้ำ

ประเภทของ RenderObject ใน Flutter

Flutter มี RenderObject หลายประเภทสำหรับงานต่าง ๆ: RenderBox สำหรับเอลิเมนต์สี่เหลี่ยมมาตรฐาน, RenderSliver สำหรับพื้นที่เลื่อนได้ และ RenderObject แบบกำหนดเองสำหรับการเรนเดอร์ที่ไม่ได้มาตรฐานผ่าน CustomPainter แต่ละประเภทถูกปรับให้เหมาะสมกับบทบาทของตนในทรีการเรนเดอร์

RenderBox และประเภทย่อย

RenderBox — คลาสพื้นฐานสำหรับเอลิเมนต์อินเทอร์เฟซทรงสี่เหลี่ยม ประเภทย่อย: RenderPadding (เพิ่มระยะห่าง), RenderTransform (ใช้การแปลง), RenderFlex (นำ Row และ Column ไปใช้), RenderStack (การซ้อนทับเอลิเมนต์), RenderImage (แสดงภาพ), RenderParagraph (แสดงข้อความ) แต่ละประเภทย่อยแทนที่ performLayout และ paint สำหรับตรรกะของตนเอง

RenderSliver และการทำเวอร์ช่วลไลเซชัน

RenderSliver — ประเภท RenderObject สำหรับทำงานกับพื้นที่เลื่อนได้ ต่างจาก RenderBox ตรงที่ Sliver ใช้ SliverConstraints ซึ่งรวมข้อมูลเกี่ยวกับพื้นที่มองเห็น (viewport) RenderSliverList และ RenderSliverGrid สร้าง RenderObject เฉพาะสำหรับเอลิเมนต์ที่อยู่ในพื้นที่มองเห็น ทำให้สามารถจัดการลิสต์ที่มีล้านรายการได้

RenderObject แบบกำหนดเองผ่าน CustomPainter

สำหรับกราฟิกที่ไม่ได้มาตรฐาน ให้ใช้ CustomPaint และ CustomPainter CustomPaint สร้าง RenderCustomPaint ที่เรียกเมธอด paint ของ CustomPainter ซึ่งช่วยให้วาดรูปร่าง กราฟ และแอนิเมชันใด ๆ ได้ด้วยการควบคุม Canvas อย่างสมบูรณ์ ตาม Flutter Team, CustomPainter มีประสิทธิภาพมากกว่าวิดเจ็ตมาตรฐานแบบซ้อนสำหรับกราฟิกเวกเตอร์ที่ซับซ้อน

dart
class CirclePainter extends CustomPainter {
  final Color color;

  CirclePainter({required this.color});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = color;
    canvas.drawCircle(
      Offset(size.width / 2, size.height / 2),
      size.width / 3,
      paint,
    );
  }

  @override
  bool shouldRepaint(CirclePainter oldDelegate) =>
    oldDelegate.color != color;
}

ในตัวอย่างนี้ CirclePainter วาดวงกลมบน Canvas เมธอด shouldRepaint ส่งคืน true เฉพาะเมื่อสีเปลี่ยน ซึ่งป้องกันการวาดซ้ำที่ไม่จำเป็น CustomPainter ควรมีน้ำหนักเบาที่สุด — การคำนวณหนักทั้งหมดควรทำนอกเมธอด paint

RenderObject Tree ถูกสร้างจาก Element Tree ผ่านกลไก RenderObjectWidget แต่ละ RenderObjectWidget (Padding, Transform, CustomPaint) สร้าง RenderObjectElement ที่สร้างและจัดการ RenderObject ที่เกี่ยวข้อง เอลิเมนต์ทำหน้าที่เป็นตัวกลาง: ส่งคอนฟิกูเรชันจากวิดเจ็ตไปยัง RenderObject และแจ้ง RenderObject เกี่ยวกับการเปลี่ยนแปลง

การสร้าง RenderObject จากเอลิเมนต์

เมื่อ RenderObjectElement ถูกเมาท์ มันจะเรียกเมธอด createRenderObject ของวิดเจ็ต วิดเจ็ตสร้างอินสแตนซ์ของ RenderObject และส่งกลับไปยังเอลิเมนต์ เอลิเมนต์แทรก RenderObject เข้าไปใน RenderObject Tree โดยเรียกเมธอด insertChildLayout ของ RenderObject หลัก กระบวนการนี้เกิดขึ้นเฉพาะในการเมาท์ครั้งแรกเท่านั้น — ในการอัปเดตครั้งถัดไป เอลิเมนต์เพียงแค่อัปเดตพารามิเตอร์ของ RenderObject ที่มีอยู่

การซิงโครไนซ์ผ่าน updateRenderObject

เมื่อคอนฟิกูเรชันของวิดเจ็ตเปลี่ยน (เช่น ค่า padding เปลี่ยน) เอลิเมนต์เรียกเมธอด updateRenderObject ซึ่งส่งคอนฟิกูเรชันใหม่ไปยัง RenderObject ที่มีอยู่ RenderObject ทำเครื่องหมายตัวเองว่า "สกปรก" สำหรับ layout หรือ paint และในเฟรมถัดไปเฟรมเวิร์กจะดำเนินการอัปเดตที่จำเป็น

การลบ RenderObject

เมื่อเอลิเมนต์ถูกอันเมาท์ เมธอด unmount จะถูกเรียก ซึ่งลบ RenderObject ออกจาก RenderObject Tree และปล่อยทรัพยากร RenderObject.remove ถูกเรียกเพื่อตัดการเชื่อมต่อจากผู้ปกครอง หลังจากนั้นออบเจ็กต์สามารถถูกเก็บโดย garbage collector Flutter รับประกันว่าไม่มี RenderObject ค้างอยู่ในทรีโดยไม่มีเอลิเมนต์ที่เกี่ยวข้อง

RepaintBoundary และการแยกการเรนเดอร์

RepaintBoundary — วิดเจ็ตที่สร้างเลเยอร์แยกต่างหากสำหรับการเรนเดอร์เนื้อหา เมื่อเนื้อหาของ RepaintBoundary เปลี่ยนแปลง เฉพาะเลเยอร์นี้เท่านั้นที่ถูกวาดซ้ำ ส่วนอื่นของหน้าจอยังคงไม่เปลี่ยนแปลง RepaintBoundary มีประโยชน์โดยเฉพาะสำหรับแอนิเมชัน เครื่องเล่นวิดีโอ กราฟแบบโต้ตอบ และเอลิเมนต์อื่น ๆ ที่อัปเดตบ่อย

RepaintBoundary ทำงานอย่างไร

หัวใจของ RepaintBoundary คือ RenderRepaintBoundary — RenderObject พิเศษที่สร้าง PictureLayer แยกต่างหาก ในการเรนเดอร์ครั้งแรก RenderRepaintBoundary บันทึกคำสั่งกราฟิกลงในเลเยอร์นี้ ในการอัปเดตครั้งถัดไป หากเฉพาะเนื้อหาภายใน RepaintBoundary เปลี่ยนแปลง Flutter จะวาดซ้ำเฉพาะเลเยอร์นี้ ไม่ใช่ทั้งหน้าจอ เลเยอร์อื่นยังคงไม่เปลี่ยนแปลงและถูกนำกลับมาใช้ใหม่

เมื่อใดควรใช้ RepaintBoundary

ไม่ใช่ว่าทุกวิดเจ็ตจำเป็นต้องมี RepaintBoundary ใช้เมื่อส่วนหนึ่งของอินเทอร์เฟซอัปเดตด้วย ความถี่สูง (60 FPS หรือสูงกว่า) ในขณะที่หน้าจอส่วนอื่นคงที่ ตัวอย่างทั่วไป: ตัวโหลดแบบแอนิเมชัน เครื่องเล่นวิดีโอ Canvas ของเกม CustomPainter ที่วาดซ้ำบ่อย สำหรับข้อความคงที่หรือปุ่ม RepaintBoundary ฟุ่มเฟือยและเพิ่มการใช้หน่วยความจำเท่านั้น

สถานการณ์คำแนะนำเหตุผล
แอนิเมชันห่อด้วย RepaintBoundaryแยกพื้นที่ที่อัปเดตบ่อย
ลิสต์เลื่อนไม่จำเป็นListView ใช้เลเยอร์อัตโนมัติ
ข้อความคงที่ไม่จำเป็นไม่มีการวาดซ้ำบ่อย
CustomPainterแนะนำการวาดกราฟิกซ้ำบ่อย

การปรับแต่ง RenderObject Tree เพื่อประสิทธิภาพ

ประสิทธิภาพ ของ RenderObject Tree ขึ้นอยู่กับจำนวนโหนด ความลึกของทรี และความถี่ในการวาดซ้ำ เครื่องมือ Flutter DevTools (แท็บ "Rendering") ช่วยให้วิเคราะห์ RenderObject Tree แบบเรียลไทม์: จำนวน repaint, เวลา layout และ paint, จำนวนเลเยอร์และขนาด การวิเคราะห์เป็นประจำช่วยระบุจุดคอขวด

หลีกเลี่ยง overdraw ที่มากเกินไป

Overdraw — สถานการณ์ที่พิกเซลหนึ่งถูกวาดหลายครั้งต่อเฟรม ตัวอย่างเช่น เมื่อวิดเจ็ตโปร่งใสซ้อนทับอีกวิดเจ็ตหนึ่ง GPU จะวาดทั้งสองเลเยอร์ ใช้แฟล็ก opaque (Container พร้อมสีแทน decoration) สำหรับเอลิเมนต์ทึบแสงเพื่อให้ Flutter ข้ามเลเยอร์ที่มองไม่เห็น ตาม Flutter Team การลด overdraw สามารถลดเวลา paint ได้ถึง 30%

ลดจำนวนเลเยอร์ให้น้อยที่สุด

แต่ละ RepaintBoundary และวิดเจ็ตบางตัว (Opacity, ClipRRect, Transform) สร้าง เลเยอร์แยก (PictureLayer) เลเยอร์มากเกินไปเพิ่มเวลาในการประกอบ ใช้การจัดกลุ่ม: แทนที่จะใช้ Opacity หลายตัวบนวิดเจ็ตแยกกัน ให้ใช้ Opacity เดียวบนคอนเทนเนอร์ แทน ClipRRect บนแต่ละเอลิเมนต์ ให้ใช้ ClipRRect บนคอนเทนเนอร์ร่วม

ใช้ const คอนสตรักเตอร์

เมื่อวิดเจ็ตถูกประกาศเป็น const Flutter รู้ว่าคอนฟิกูเรชันของมันจะไม่เปลี่ยนแปลงและสามารถนำ RenderObject ที่เกี่ยวข้องกลับมาใช้ใหม่ได้โดยไม่ต้องสร้างใหม่ const คอนสตรักเตอร์ลดภาระบน garbage collector และเร่งเฟรมแรก ใช้ const สำหรับวิดเจ็ตที่มีพารามิเตอร์คงที่: ไอคอน หัวเรื่อง เอลิเมนต์ตกแต่ง

dart
const Text("ชื่อ", style: TextStyle(fontSize: 24));
const Icon(Icons.home, color: Colors.blue);
const SizedBox.shrink();

คำถามที่พบบ่อย

RenderObject Tree แตกต่างจาก Widget Tree อย่างไร?

Widget Tree — คอนฟิกูเรชันน้ำหนักเบาของอินเทอร์เฟซที่ถูกสร้างใหม่ทุกครั้งที่มีการ rebuild RenderObject Tree — ทรีหนักของออบเจ็กต์การเรนเดอร์ที่คงอยู่และอัปเดตเฉพาะเมื่อเรขาคณิตหรือลักษณะภายนอกเปลี่ยนแปลง

จะดู RenderObject Tree ในดีบักเกอร์ได้อย่างไร?

ใช้ Flutter DevTools — แท็บ "Rendering" คุณจะเห็นเลเยอร์การเรนเดอร์ เวลา layout และ paint รวมถึงข้อมูลโดยละเอียดเกี่ยวกับแต่ละ RenderObject: ขนาด, constraints, แฟล็กความต้องการอัปเดต

dirty RenderObject คืออะไร?

Dirty — RenderObject ที่ถูกทำเครื่องหมายว่าต้องการอัปเดต แฟล็ก _needsLayout หรือ _needsPaint ถูกตั้งค่าเมื่อคอนฟิกูเรชันเปลี่ยนแปลง และ Flutter จะดำเนินการ layout หรือ paint สำหรับโหนดนี้ในเฟรมถัดไป

ฉันสามารถสร้าง RenderObject ของตัวเองได้หรือไม่?

ได้, สร้างคลาสย่อยของ RenderBox และแทนที่เมธอด performLayout และ paint ใช้ RenderObjectWidget เพื่อแทรก RenderObject ที่กำหนดเองเข้าไปใน Widget Tree นี่เป็นเทคนิคขั้นสูงสำหรับการเรนเดอร์ที่ไม่ได้มาตรฐาน

RepaintBoundary ส่งผลต่อ RenderObject Tree อย่างไร?

RepaintBoundary สร้าง RenderRepaintBoundary ที่แยกส่วนของ RenderObject Tree ออกเป็นเลเยอร์แยกต่างหาก เมื่อเนื้อหาเปลี่ยนแปลง เฉพาะเลเยอร์นี้ถูกวาดซ้ำ ส่วนที่เหลือของทรียังคงไม่เปลี่ยนแปลง

สรุป

  • RenderObject Tree — ระดับที่สามของสถาปัตยกรรม Flutter ที่รับผิดชอบ layout และ paint ของแต่ละเอลิเมนต์อินเทอร์เฟซ
  • แต่ละ RenderObject ดำเนินสองเฟส: layout (การคำนวณขนาดและตำแหน่ง) และ paint (การวาดพิกเซลผ่าน Canvas)
  • RenderBox — ประเภทพื้นฐานสำหรับเอลิเมนต์มาตรฐาน, RenderSliver — สำหรับเวอร์ช่วลไลเซชันของลิสต์เลื่อน
  • RenderObject Tree ซิงโครไนซ์กับ Element Tree ผ่าน RenderObjectElement ที่สร้างและอัปเดต RenderObject
  • RepaintBoundary แยกส่วนของทรีออกเป็นเลเยอร์แยก ป้องกันการวาดซ้ำทั้งหน้าจอเมื่อมีการเปลี่ยนแปลงเฉพาะที่
  • ประสิทธิภาพ ขึ้นอยู่กับความลึกของทรี จำนวนเลเยอร์ overdraw และการใช้ const คอนสตรักเตอร์
  • Flutter DevTools มีเครื่องมือสำหรับวิเคราะห์ RenderObject Tree: เวลา layout, paint, จำนวนเลเยอร์และ repaint

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม