List not populating in Flutter

huangapple go评论62阅读模式
英文:

List not populating in Flutter

问题

我正在尝试创建一个表单,当我填写它时,将填充一个ListView,但似乎无法使列表填充任何值。

我正在使用以下代码来创建底部导航:

class _AppState extends State<App> {
  int _currentIndex = 0;
  final List<Widget> body = [
    AddNewStudent(),
    StudentList(),
  ];

在一个包含表单的文件中,代码如下:

class StudentClass {
  String kidFirstName;
  String kidLastName;
  DateTime dateOfBirth;
  int totalAttendance = 0;
  int attendanceAtRank = 0;

  StudentClass(
      {required this.kidFirstName,
      required this.kidLastName,
      required this.dateOfBirth});
}

class AddNewStudent extends StatefulWidget {
  @override
  AddStudentScreen createState() => AddStudentScreen();
}

class AddStudentScreen extends State<AddNewStudent> {
  List<StudentClass> studentList = [];
  void addStudent(StudentClass newStudent) {
    setState(() {
      studentList.add(newStudent);
    });
  }

  final formKey = GlobalKey<FormState>();
  Widget build(BuildContext context) {
    return Container(
        margin: EdgeInsets.all(20.0),
        child: SingleChildScrollView(
            child: Column(
          children: [
            Form(
              key: formKey,
              child: Column(
                children: [
                  kidsFirstNameFormField(),
                  kidLastNameFormField(),
                  kidDateOfBirth(),
                  submitButton(),
                ],
              ),
            ),
          ],
        )));
  }

  Widget submitButton() {
    return ElevatedButton(
      child: Text('Create New Student Profile'),
      onPressed: () {
        if (formKey.currentState?.validate() ?? false) {
          formKey.currentState?.save();
          StudentClass newStudent = StudentClass(
            kidFirstName: kidFirstName,
            kidLastName: kidLastName,
            dateOfBirth: dateOfBirth,
          );
          addStudent(newStudent);
          formKey.currentState?.reset();
        }
      },
    );
  }

ListView构建器在它自己的文件中:

class StudentList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    List<StudentClass> studentList = [];
    return Scaffold(
      appBar: AppBar(
        title: Text('Student List'),
      ),
      body: StudentListState(
        studentList: studentList,
      ),
    );
  }
}

class StudentListState extends StatefulWidget {
  final List<StudentClass> studentList;
  StudentListState({required this.studentList});
  @override
  _StudentListState createState() => _StudentListState();
}

class _StudentListState extends State<StudentListState> {
  void addStudent(StudentClass student) {
    setState(() {
      widget.studentList.add(student);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        margin: EdgeInsets.all(20.0),
        child: ListView.builder(
          itemCount: widget.studentList.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(widget.studentList[index].kidFirstName),
              subtitle: Text(widget.studentList[index].kidLastName),
              trailing: Text(widget.studentList[index].dateOfBirth.toString()),
            );
          },
        ));
  }
}

我在弄清如何将信息传递到列表以进行填充方面遇到了困难。我已经成功构建了没有错误,但我知道我没有正确传递信息。我知道我可能在这里有一个额外的列表。

英文:

I am trying to have a form when I fill it out will populate a ListView, but can't seem to get the list to popluate with any values.

I am using the following to have a bottom navigation:

class _AppState extends State&lt;App&gt; {
  int _currentIndex = 0;
  final List&lt;Widget&gt; body = [
    AddNewStudent(),
    StudentList(),
  ];

In a file that has the form looks like this:

class StudentClass {
  String kidFirstName;
  String kidLastName;
  DateTime dateOfBirth;
  int totalAttedance = 0;
  int attedanceAtRank = 0;

  StudentClass(
      {required this.kidFirstName,
      required this.kidLastName,
      required this.dateOfBirth});
}

class AddNewStudent extends StatefulWidget {
  @override
  AddStudentScreen createState() =&gt; AddStudentScreen();
}

class AddStudentScreen extends State&lt;AddNewStudent&gt; {
  List&lt;StudentClass&gt; studentList = [];
  void addStudent(StudentClass newStudent) {
    setState(() {
      studentList.add(newStudent);
    });
  }
  
  final formKey = GlobalKey&lt;FormState&gt;();
Widget build(BuildContext context) {
    return Container(
        margin: EdgeInsets.all(20.0),
        child: SingleChildScrollView(
            child: Column(
          children: [
            Form(
              key: formKey,
              child: Column(
                children: [
                  kidsFirstNameFormField(),
                  kidLastNameFormField(),
                  kidDateofBirth(),
                  submitButton(),
                ],
              ),
            ),
          ],
        )));
  }
Widget submitButton() {
    return ElevatedButton(
      child: Text(&#39;Create New Student Profile&#39;),
      onPressed: () {
        if (formKey.currentState?.validate() ?? false) {
          formKey.currentState?.save();
          StudentClass newStudent = StudentClass(
            kidFirstName: kidFirstName,
            kidLastName: kidLastName,
            dateOfBirth: dateOfBirth,
          );
          addStudent(newStudent);
          formKey.currentState?.reset();
        }
      },
    );
  }

The listview builder is in its own file:

class StudentList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    List&lt;StudentClass&gt; studentList = [];
    return Scaffold(
      appBar: AppBar(
        title: Text(&#39;Student List&#39;),
      ),
      body: StudentListState(
        studentList: studentList,
      ),
    );
  }
}

class StudentListState extends StatefulWidget {
  final List&lt;StudentClass&gt; studentList;
  StudentListState({required this.studentList});
  @override
  _StudentListState createState() =&gt; _StudentListState();
}

class _StudentListState extends State&lt;StudentListState&gt; {
  void addStudent(StudentClass student) {
    setState(() {
      widget.studentList.add(student);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        margin: EdgeInsets.all(20.0),
        child: ListView.builder(
          itemCount: widget.studentList.length,
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(widget.studentList[index].kidFirstName),
              subtitle: Text(widget.studentList[index].kidLastName),
              trailing: Text(widget.studentList[index].dateOfBirth.toString()),
            );
          },
        ));
  }
}

I am pretty stuck on figuring out how to pass the information over to the list to populate. I have gotten it to build with no errors but somehow I know I am not passing it correctly. I know I might have an extra list in here.

答案1

得分: 1

你正在更新AddStudentScreen小部件的studentList。在ListView中,您正在渲染来自StudentList小部件的studentList,这是一个不同的变量并且始终为空。

此外,您在build函数内初始化了studentList,这意味着每次调用setState()时,studentList都会被初始化为空列表。

看起来您想在多个小部件中使用相同的数据。在这种情况下,考虑使用状态管理器。

对于您的情况,我建议您使用stream_mixin

示例:

  • 使用stream_mixin包创建学生服务StoreService
class StudentModel extends BaseModel { // 注意这一点
  String kidFirstName;
  String kidLastName;
  DateTime dateOfBirth;
  int totalAttedance = 0;
  int attedanceAtRank = 0;

  StudentModel({
    required this.kidFirstName,
    required this kidLastName,
    required this dateOfBirth,
    required String id,
  }) : super(id: id);
}

class StudentService extends StoreService<StudentModel> { // 注意这一点
  StudentService._();
  static StudentService store = StudentService._(); // 仅创建了StudentService的单例。
}
  • 向存储中添加学生数据(注意,这可以在应用程序的任何地方完成):
const student = new StudentModel(
  // 在这里添加学生数据
)
StudentService.store.add(student);
  • 渲染学生列表
StreamBuilder<StudentModel>(
  stream: StudentService.store.onChange,
  builder: (context, snapshot) {
    if (snapshot.data == null) {
      return Text("尚未添加学生。");
    }
    return ListView.builder(
      itemCount: StudentService.store.values.length,
      itemBuilder: (context, index) {
        const student = StudentService.store.values[index];
        return ListTile(
          title: Text(student.kidFirstName),
          subtitle: Text(student.kidLastName),
          trailing: Text(student.dateOfBirth.toString()),
        );
      },
    )
  },
)

现在,每当您使用StudentService.store.add()添加学生数据时,它将发出一个事件,您的SteamBuilder会监听stream: StudentService.store.onChange,并更新UI以显示更新的列表。

这还将消除使用StatefulWidget的必要性。这意味着除非您需要为其他事情使用StatefulWidget,否则只能使用StatelessWidget

英文:

You are updating the studentList of the AddStudentScreen widget. And in the ListView you are rendering the studentList from StudentList widget which is a different variable and is always empty.

Also, you are initialising studentList inside the build function which means that on every setState() studentList will be initialised to an empty list.

Seems like you want to use the same data in multiple widgets. In such cases consider using a state manager.

For you scenario, I'd recommend you use stream_mixin.

Example:

  • Create student service using StoreService from stream_mixin package.
class StudentModel extends BaseModel { // NOTICE THIS
  String kidFirstName;
  String kidLastName;
  DateTime dateOfBirth;
  int totalAttedance = 0;
  int attedanceAtRank = 0;

  StudentModel({
    required this.kidFirstName,
    required this.kidLastName,
    required this.dateOfBirth,
    required String id,
  }) : super(id: id);
}

class StudentService extends StoreService&lt;StudentModel&gt; { // NOTICE THIS
  StudentService._();
  static StudentService store = StudentService._(); // Just creating a singleton for StudentService.
}
  • To add student data in the store (note, this can be done anywhere in the app):
const student = new StudentModel(
  // add student data here
)
StudentService.store.add(student);
  • Render this list of students
StreamBuilder&lt;StudentModel&gt;(
  stream: StudentService.store.onChange,
  builder: (context, snapshot) {
    if (snapshot.data == null) {
      return Text(&quot;No student added yet.&quot;);
    }
    return ListView.builder(
      itemCount: StudentService.store.values.length,
      itemBuilder: (context, index) {
        const student = StudentService.store.values[index];
        return ListTile(
          title: Text(student.kidFirstName),
          subtitle: Text(student.kidLastName),
          trailing: Text(student.dateOfBirth.toString()),
        );
      },
    )
  },
)

Now, every time you add student data using StudentService.store.add(), it will emit an event which your SteamBuilder with stream: StudentService.store.onChange is listening and will update the UI to show the updated list.

This will also eliminate the necessity of StatefulWidget. Which means you can use only StatelessWidget unless otherwise you require StatefulWidget for something else.

huangapple
  • 本文由 发表于 2023年2月16日 03:48:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464788.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定