วิธีใช้ CustomMultiChildLayout & CustomSingleChildLayout ใน Flutter


10

คนที่มีประสบการณ์ในการใช้CustomSingleChildLayoutและCustomMultiChildLayoutชั้นเรียนสามารถอธิบายรายละเอียด (พร้อมตัวอย่าง) ในวิธีการใช้งานได้หรือไม่

ฉันยังใหม่กับ Flutter และพยายามเข้าใจวิธีใช้สิ่งเหล่านี้ อย่างไรก็ตามเอกสารน่ากลัวและไม่ชัดเจน ฉันพยายามกลั้วอินเทอร์เน็ตเพื่อเป็นตัวอย่าง แต่ไม่มีเอกสารอื่นใด

ฉันจะขอบคุณตลอดไปหากคุณสามารถช่วยได้

ขอบคุณ!


คุณกรุณาเพิ่มสิ่งที่คุณต้องการใช้เพื่อ
João Soares

@ JoãoSoaresไม่ต้องกังวลกับเรื่องนี้เพราะฉันกำลังเขียนคำตอบมากมาย
creativecreatorormaybenot

ความคาดหวังสูงแล้ว!
João Soares

@ JoãoSoaresเรียบร้อยแล้วแจ้งให้เราทราบหากคุณมีการแก้ไขใด ๆ
creativecreatorormaybenot

@creativecreatorormaybenot นั่นคงไม่น่าเป็นไปได้ ฉันเคยเห็นคำตอบของคุณมาก่อน คำตอบที่ดีเช่นเคย
João Soares

คำตอบ:


20

ก่อนอื่นฉันอยากจะบอกว่าฉันดีใจที่ได้ช่วยคุณในเรื่องนี้เพราะฉันสามารถเข้าใจการดิ้นรนของคุณได้ - มีประโยชน์ในการหาคำตอบด้วยตัวเองเช่นกัน

อะไรCustomSingleChildLayoutจะชัดเจนหลังจากที่ฉันอธิบายCustomMultiChildLayoutให้คุณทราบ

CustomMultiChildLayout

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

CustomMultiChildLayout(
  children: [
    // Widgets you want to layout in a customized manner
  ],
)

ตอนนี้มีอีกสองขั้นตอนที่คุณต้องทำก่อนที่จะเริ่มวางลูกของคุณ:

  1. เด็กที่คุณส่งผ่านไปยังทุกchildrenความต้องการที่จะเป็นและคุณผ่านเครื่องมือที่คุณต้องการจริงที่จะแสดงความเป็นเด็กไปว่าLayoutId LayoutIdThe idจะระบุวิดเจ็ตของคุณโดยไม่ซ้ำกันทำให้พวกเขาสามารถเข้าถึงได้เมื่อจัดวาง:
CustomMultiChildLayout(
  children: [
    LayoutId(
      id: 1, // The id can be anything, i.e. any Object, also an enum value.
      child: Text('Widget one'), // This is the widget you actually want to show.
    ),
    LayoutId(
      id: 2, // You will need to refer to that id when laying out your children.
      child: Text('Widget two'),
    ),
  ],
)
  1. คุณต้องสร้างMultiChildLayoutDelegateคลาสย่อยที่จัดการส่วนเลย์เอาต์ เอกสารที่นี่ดูเหมือนจะซับซ้อนมาก
class YourLayoutDelegate extends MultiChildLayoutDelegate {
  // You can pass any parameters to this class because you will instantiate your delegate
  // in the build function where you place your CustomMultiChildLayout.
  // I will use an Offset for this simple example.

  YourLayoutDelegate({this.position});

  final Offset position;
}

ตอนนี้การตั้งค่าทั้งหมดเสร็จสิ้นแล้วและคุณสามารถเริ่มนำเค้าโครงจริงไปใช้ มีสามวิธีที่คุณสามารถใช้เพื่อ:

  • hasChildซึ่งช่วยให้คุณตรวจสอบว่ามีการส่งรหัสเฉพาะ(จำได้LayoutIdไหม) ไปที่หรือไม่childrenนั่นคือถ้ามีรายการย่อยของรหัสนั้น

  • layoutChildซึ่งคุณต้องโทรหาทุกidเด็กทุกคนที่มีให้ครั้งเดียวและมันจะให้คุณSizeของเด็กคนนั้น

  • positionChildซึ่งช่วยให้คุณเปลี่ยนตำแหน่งจากOffset(0, 0)เป็นออฟเซ็ตใด ๆ ที่คุณระบุ

ฉันรู้สึกว่าแนวคิดควรมีความชัดเจนในตอนนี้ซึ่งเป็นเหตุผลที่ฉันจะอธิบายวิธีการนำผู้ได้รับมอบหมายมาเป็นตัวอย่างCustomMultiChildLayout:

class YourLayoutDelegate extends MultiChildLayoutDelegate {
  YourLayoutDelegate({this.position});

  final Offset position;

  @override
  void performLayout(Size size) {
    // `size` is the size of the `CustomMultiChildLayout` itself.

    Size leadingSize = Size.zero; // If there is no widget with id `1`, the size will remain at zero.
    // Remember that `1` here can be any **id** - you specify them using LayoutId.
    if (hasChild(1)) {
      leadingSize = layoutChild(
        1, // The id once again.
        BoxConstraints.loose(size), // This just says that the child cannot be bigger than the whole layout.
      );
      // No need to position this child if we want to have it at Offset(0, 0).
    }

    if (hasChild(2)) {
      final secondSize = layoutChild(
        2,
        BoxConstraints(
          // This is exactly the same as above, but this can be anything you specify.
          // BoxConstraints.loose is a shortcut to this.
          maxWidth: size.width,
          maxHeight: size.height,
        ),
      );

      positionChild(
        2,
        Offset(
          leadingSize.width, // This will place child 2 to the right of child 1.
          size.height / 2 - secondSize.height / 2, // Centers the second child vertically.
        ),
      );
    }
  }
}

สองตัวอย่างอื่น ๆ เป็นหนึ่งจาก (การเตรียมการตรวจสอบเอกสารขั้นตอนที่ 2 ) และโลกแห่งความจริงตัวอย่างเช่นผมเขียนกลับมาบางครั้งสำหรับfeature_discoveryแพคเกจ: MultiChildLayoutDelegateการดำเนินงานและCustomMultiChildLayoutในbuildวิธีการ

ขั้นตอนสุดท้ายคือการเอาชนะshouldRelayoutวิธีซึ่งควบคุมง่าย ๆ ว่าperformLayoutควรจะเรียกอีกครั้ง ณ จุดใดก็ตามในเวลาโดยเปรียบเทียบกับผู้แทนเก่า (เลือกที่คุณสามารถแทนที่getSize) และเพิ่มผู้แทนลงในCustomMultiChildLayout:

class YourLayoutDelegate extends MultiChildLayoutDelegate {
  YourLayoutDelegate({this.position});

  final Offset position;

  @override
  void performLayout(Size size) {
    // ... (layout code from above)
  }

  @override
  bool shouldRelayout(YourLayoutDelegate oldDelegate) {
    return oldDelegate.position != position;
  }
}
CustomMultiChildLayout(
  delegate: YourLayoutDelegate(position: Offset.zero),
  children: [
    // ... (your children wrapped in LayoutId's)
  ],
)

การพิจารณา

  • ฉันใช้1และ2เป็นidในตัวอย่างนี้ แต่การใช้enumอาจเป็นวิธีที่ดีที่สุดในการจัดการรหัสถ้าคุณมีรหัสเฉพาะ

  • คุณสามารถส่งผ่านListenableไปยังsuper(เช่นsuper(relayout: animation)) หากคุณต้องการเคลื่อนไหวกระบวนการจัดวางหรือเรียกใช้งานโดยอิงจากการฟังโดยทั่วไป

CustomSingleChildLayout

เอกสารอธิบายสิ่งที่ฉันอธิบายไว้ข้างต้นได้ดีมากและที่นี่คุณจะเห็นว่าทำไมฉันถึงบอกว่าCustomSingleChildLayoutจะชัดเจนมากหลังจากเข้าใจวิธีการCustomMultiChildLayoutทำงาน:

CustomMultiChildLayoutเหมาะสมเมื่อมีความสัมพันธ์ที่ซับซ้อนระหว่างขนาดและการวางตำแหน่งของวิดเจ็ตหลายรายการ ในการควบคุมเค้าโครงของลูกคนเดียวCustomSingleChildLayoutเหมาะสมกว่า

นี่ก็หมายความว่าการใช้เป็นCustomSingleChildLayoutไปตามหลักการเดียวกับที่ฉันอธิบายไว้ข้างต้น แต่ไม่มีรหัสใด ๆ เพราะมีเพียงเด็กคนเดียว
คุณต้องใช้SingleChildLayoutDelegateแทนซึ่งมีวิธีการที่แตกต่างกันสำหรับการใช้เลย์เอาต์ (พวกเขาทั้งหมดมีพฤติกรรมเริ่มต้นดังนั้นพวกเขาในทางเทคนิคทั้งหมดเป็นทางเลือกที่จะแทนที่ ):

  • getConstraintsForChildซึ่งเทียบเท่ากับข้อ จำกัด ที่ฉันส่งไปlayoutChildด้านบน

  • getPositionForChildซึ่งเทียบเท่ากับpositionChildข้างต้น

ทุกอย่างอื่นเหมือนกันหมด (จำไว้ว่าคุณไม่ต้องการLayoutIdและมีลูกเพียงคนเดียวแทนที่จะเป็นchildren)


MultiChildRenderObjectWidget

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

CustomMultiChildLayout ไม่สามารถปรับขนาดตัวเองตามลูกหลานของตน (ดูปัญหาเกี่ยวกับเอกสารที่ดีกว่าสำหรับการให้เหตุผล )

ฉันจะไม่อธิบายวิธีใช้MultiChildRenderObjectWidgetที่นี่ด้วยเหตุผลที่ชัดเจน แต่หากคุณสนใจคุณสามารถตรวจสอบการส่งของฉันต่อความท้าทายนาฬิกา Flutterหลังจากวันที่ 20 มกราคม 2020 ซึ่งฉันใช้MultiChildRenderObjectWidgetอย่างกว้างขวาง - คุณสามารถอ่านบทความเกี่ยวกับเรื่องนี้ได้ ซึ่งควรอธิบายเล็กน้อยว่ามันทำงานอย่างไร

สำหรับตอนนี้คุณสามารถจำได้ว่าMultiChildRenderObjectWidgetเป็นสิ่งที่ทำให้CustomMultiChildLayoutเป็นไปได้และการใช้งานโดยตรงจะให้ประโยชน์ที่ดีบางอย่างแก่คุณเช่นไม่ต้องใช้LayoutIdและแทนที่จะสามารถเข้าถึงRenderObjectข้อมูลผู้ปกครองของโดยตรง

สนุกกับความเป็นจริง

ฉันเขียนรหัสทั้งหมดในข้อความล้วน (ในฟิลด์ข้อความ StackOverflow) ดังนั้นหากมีข้อผิดพลาดโปรดชี้ให้ฉันและฉันจะแก้ไข


1
ว้าว. คำตอบที่น่าอัศจรรย์ ควรLayoutIdเป็นเอกลักษณ์ทั่วโลกหรือในประเทศหรือไม่ ทั่วโลกเช่นวิดเจ็ตพี่น้องประเภทCustomMultiChildLayoutต้องมีความชัดเจนLayoutIdในลูก
om-ha

1
@ om-ha ในเครื่อง - รหัสจะถูกเก็บไว้ในข้อมูลผู้ปกครองของLayoutIdซึ่งหมายความว่าข้อมูลนี้จะถูกเข้าถึงได้โดยผู้ปกครองโดยตรงเท่านั้น :)
creativecreatorormaybenot

2
ว้าว! คุณคือผู้ช่วยให้รอดของฉัน! นี่คือสิ่งที่ฉันพูดคุยเกี่ยวกับ! นี่คือวิธีที่เอกสารควรมีการกระพือ !! ไม่มีทางที่ฉันจะสามารถคิดออกได้ว่าคลาสเหล่านี้ทำงานกับเอกสารปกติได้อย่างไร ขอบคุณมาก!
วอลเตอร์ M

1
คำตอบที่น่าอัศจรรย์จริงๆ CustomMultiChildLayoutจะเป็นประโยชน์มากในสถานการณ์ที่คุณต้องการไปยังกลุ่มอัตโนมัติปรับขนาดวิดเจ็ตข้อความหลายรายการภายในColumnของRow's สำหรับตัวอย่าง
om-ha
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.