ส่งผ่านข้อมูลไปยัง StatefulWidget และเข้าถึงข้อมูลในสถานะใน Flutter


130

ฉันมี 2 หน้าจอในแอพ Flutter ของฉัน: รายการบันทึกและหน้าจอสำหรับสร้างและแก้ไขบันทึก

ถ้าฉันส่งวัตถุไปยังหน้าจอที่สองนั่นหมายความว่าฉันกำลังจะแก้ไขสิ่งนี้และถ้าฉันผ่านค่าว่างหมายความว่าฉันกำลังสร้างรายการใหม่ การแก้ไขหน้าจอเป็นวิดเจ็ตสถานะและฉันไม่แน่ใจว่าจะใช้แนวทางนี้อย่างไรhttps://flutter.io/cookbook/navigation/passing-data/สำหรับกรณีของฉัน

class RecordPage extends StatefulWidget {
  final Record recordObject;

  RecordPage({Key key, @required this.recordObject}) : super(key: key);

  @override
  _RecordPageState createState() => new _RecordPageState();
}

class _RecordPageState extends State<RecordPage> {
  @override
  Widget build(BuildContext context) {
   //.....
  }
}

ฉันจะเข้าถึงrecordObjectภายใน_RecordPageState ได้อย่างไร



เราจะใช้ค่าตัวแปร 'recordObject' ในฟังก์ชันของคลาส _RecordPageState ได้อย่างไร
Kamlesh

คำตอบ:


215

ในการใช้ recordObject ใน _RecordPageState คุณต้องเขียน widget.objectname ดังด้านล่าง

class _RecordPageState extends State<RecordPage> {
  @override
  Widget build(BuildContext context) {
   .....
   widget.recordObject
   .....
  }
}

9
ใครที่ยังใหม่กับ Flutter อย่าลืมกำหนดวิดเจ็ตเช่น '@override RecordPage get widget => super.widget;'
hhk

22
@hhk ทำไมถึงจำเป็น?
Herohtar

2
should't recordObjectส่วนหนึ่งต้องมีStateระดับ? เหตุผลที่มีมันStatefulWidgetไม่ถูกต้อง (ในแง่ของการทำงานร่วมกัน) นอกจากนี้ทุกฟิลด์StatefulWidgetควรไม่เปลี่ยนรูป - ถ้าคุณต้องการเปลี่ยนrecordObjectข้อมูลอ้างอิงล่ะ?
Alex Semeniuk

ฉันมีเหมือนกันทุกText(widget.recordObject)
Dani

เราจะใช้ค่าตัวแปร 'recordObject' ในฟังก์ชันของคลาส _RecordPageState ได้อย่างไร
Kamlesh

33
class RecordPage extends StatefulWidget {
  final Record recordObject;

  RecordPage({Key key, @required this.recordObject}) : super(key: key);

  @override
  _RecordPageState createState() => new _RecordPageState(recordObject);
}

class _RecordPageState extends State<RecordPage> {
  Record  recordObject
 _RecordPageState(this. recordObject);  //constructor
  @override
  Widget build(BuildContext context) {.    //closure has access
   //.....
  }
}

1
โปรดอธิบายว่าเหตุใดจึงเป็นวิดเจ็ตที่มีสถานะสมบูรณ์
localhoost

@atilkan เนื่องจากสคริปต์เริ่มต้นของ OP เป็น StatefulWidget เขาเพิ่งเพิ่มบางบรรทัดเพื่อให้เหมาะกับความต้องการ
adadion

3
ฉันไม่คิดว่าการมีrecordObjectสนามทั้งในStateและStatefulWidgetชั้นเรียนจะเป็นความคิดที่ดี (แม้ว่าฉันจะเห็นบทแนะนำที่ทำเช่นนี้ก็ตาม) วิธีการเข้าถึงฟิลด์StatefulWidgetโดยใช้widgetสาขาวิชาStateดูเหมือนจะเป็นแนวทางที่ถูกต้องกว่า (แม้ว่าจะมีปัญหาในตัวเองก็ตาม)
Alex Semeniuk

24

ตัวอย่างเต็ม

คุณไม่จำเป็นต้องส่งพารามิเตอร์ไปยังสถานะโดยใช้ตัวสร้าง คุณสามารถเข้าถึงเหล่านี้โดยใช้widget.myField

class MyRecord extends StatefulWidget {
  final String recordName;
  const MyRecord(this.recordName);

  @override
  MyRecordState createState() => MyRecordState();
}

class MyRecordState extends State<MyRecord> {
  @override
  Widget build(BuildContext context) {
    return Text(widget.recordName); // Here you direct access using widget
  }
}

ส่งผ่านข้อมูลของคุณเมื่อคุณนำทางหน้าจอ:

 Navigator.of(context).push(MaterialPageRoute(builder: (context) => MyRecord("WonderWorld")));

0

บ่อยครั้งคุณไม่เพียงต้องการนำทางไปยังหน้าจอใหม่ แต่ยังส่งข้อมูลไปยังหน้าจอด้วย ตัวอย่างเช่นคุณอาจต้องการส่งข้อมูลเกี่ยวกับรายการที่ถูกแตะ

ในตัวอย่างนี้สร้างรายการสิ่งที่ต้องทำ เมื่อแตะสิ่งที่ต้องทำให้ไปที่หน้าจอใหม่ (วิดเจ็ต) ที่แสดงข้อมูลเกี่ยวกับบันทึก สูตรนี้ใช้ขั้นตอนต่อไปนี้:

  • กำหนดคลาส RecordObject
  • สร้างไฟล์StatelessWidget. เราเรียกมันว่า RecordsScreen (สำหรับ: แสดงรายการระเบียน)
  • สร้างหน้าจอรายละเอียดที่สามารถแสดงข้อมูลเกี่ยวกับบันทึก
  • นำทางและส่งข้อมูลไปยังหน้าจอรายละเอียด

กำหนดคลาส RecordObject

class RecordObject {
  final String title;
  final String description;

  RecordObject(this.title, this.description);
}

สร้างคลาส RecordsScreen

class RecordsScreen extends StatelessWidget {
   List<RecordObject> records;

  RecordsScreen({Key key, @required this.records}) : super(key: key);

  @override
  Widget build(BuildContext context) {
     records = List<RecordObject>.generate(20,
      (i) => RecordObject(
      'Record $i',
      'A description of what needs to be done for Record $i',
      ),
     );
    return Scaffold(
      appBar: AppBar(
        title: Text('Records'),
      ),
      body: ListView.builder(
        itemCount: records.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(records[index].title),
            // When a user taps the ListTile, navigate to the DetailScreen.
            // Notice that you're not only creating a DetailScreen, you're
            // also passing the current todo through to it.
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => DetailScreen(recordObject: records[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

สร้างหน้าจอรายละเอียด - ชื่อของหน้าจอประกอบด้วยชื่อของบันทึกและเนื้อหาของหน้าจอจะแสดงคำอธิบาย

class DetailScreen extends StatelessWidget {
  // Declare a field that holds the RecordObject.
  final RecordObject recordObject;

  // In the constructor, require a RecordObject.
  DetailScreen({Key key, @required this.recordObject}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // Use the RecordObject to create the UI.
    return Scaffold(
      appBar: AppBar(
        title: Text(recordObject.title),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Text(recordObject.description),
      ),
    );
  }
}

ป้อนคำอธิบายภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.