具有提供程序的可空 class 实例

Nullable class instance with Provider

我有一个名为 User 的 class,它基本上有两个变量。 nameage。另外,我还有一个名为 UserList 的 class。这个 class 的目的是将 user 对象添加到列表中,并 return 该列表。

用户模型

class User with ChangeNotifier{
    late String? name;
    late int? age;

  //set user name;
  setName(String name){
    this.name=name;
  }

  //set user age
  setAge(int age){
    this.age=age;
  }

}

用户列表class


class UserList with ChangeNotifier{
  final List<User> _list=[];

  //add a new user to the list.
  void addUserToList(User user){
  _list.add(user);
  notifyListeners();
  }
  //return the private list of users.
List<User>getUsers() =>_list;


}

这是场景。我想从一页插入一个值并在第二页上查看插入的值。看下面的图片。在第一页,

  1. 我插入 agename
  2. User 对象实例中分配这些值 (user.setName, user.setAge)
  3. UserList 列表中添加 user 对象实例
  4. 使用 provider 提供该列表。(Provider.of<UserList>(context).addUserToList(user);

首页

首页代码


void main() {
  runApp(

      MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (context) => UserList()),
            ChangeNotifierProvider(create: (context) => User()),
          ],
          child: const MyApp())
  
  );
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}
class MyHomePage extends StatelessWidget {
  TextEditingController nameController = TextEditingController();
  TextEditingController ageController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    User user =User();
    return Scaffold(
      backgroundColor: Colors.grey[300],
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
              TextField(
                controller: nameController,
                decoration: const InputDecoration(
                  hintText: "Name",
                ),
              ),
            TextField(
              controller: ageController,
              decoration: const InputDecoration(
                hintText: "Age",
              ),
            ),
            ElevatedButton(onPressed: (){
             //providing userList
                user.setName(nameController.text); //setting user name
                user.setAge(int.parse(ageController.text)); // setting user age
               Provider.of<UserList>(context,listen: false).addUserToList(user); //providing the list of users
                nameController.text=""; //after insertion, clearing the text field
                ageController.text="";//after insertion, clearing the text field
                user=User(); // instantiating a new user object for the following insertion.
                Navigator.push(context, MaterialPageRoute(builder: (context)=>const ViewUser()));
            }, child: const Text("Submit"))

          ],
        ),
      ),
    );
  }
}


在第二页上,在 ListView 中显示那些插入的值。让我们回到主要问题。 ListView的每一项都包裹着一个GestureDetector,以便能够获得functionality.I希望到目前为止一切都清楚。 问题是; 当我点击每个项目时我想return到first page。但是,这次 TextField 不应该为空。它必须替换为该项目的值。例如。如果我点击 John Nash43。第一页必须弹出该列表项的字段值。 为了能够做到这一点,我使用另一个 Provider 来提供 User 对象。但是,由于空安全性,我无法这样做,它给出了关于用户对象为空的错误。有什么有用的想法吗?

第二页

第二页代码

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

  @override
  Widget build(BuildContext context) {
    List<User> userList = Provider.of<UserList>(context).getUsers();
    return Scaffold(
      appBar: AppBar(
        title: const Text("Users List"),
      ),
      body: ListView.builder(
          padding: const EdgeInsets.all(8),
          itemCount: userList.length,
          itemBuilder: (BuildContext context, int index) {
            return Column(
              children: [
                const SizedBox(height: 15,),
                GestureDetector(
                  onTap: (){
                    Provider.of<User>(context,listen: false)
                        .setName(userList[index].name!);
                    Provider.of<User>(context,listen: false)
                        .setAge(userList[index].age!);
                    Navigator.push(context, MaterialPageRoute(builder: (context)=>MyHomePage()));
                  },
                  child: Container(
                    height: 50,
                    color: Colors.amber,
                    child: Center(
                      child: Row(
                        children: [
                          Text("Name: " + userList[index].name!),
                          const SizedBox(
                            width: 40,
                          ),
                          Text("Age:" + userList[index].age.toString()),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            );
          }),
    );
  }
}

当您使用 Navigator.push 时,您可以将用户作为 arguments

GestureDetector(
  onTap: () {
    final user = userList[index];
    Navigator.push(
      context,
      MaterialPageRoute(
          builder: (context) => MyHomePage(),
          settings: RouteSettings(
            arguments: user,
          )),
    );
  },

MyHomePage 构建方法将是

 @override
  Widget build(BuildContext context) {
    User user = User();
    User? args = ModalRoute.of(context)?.settings.arguments as User?;

    if (args != null) {
      nameController.text = args.name ?? "";
      ageController.text = args.age.toString();
    }
    return Scaffold(....

在这种情况下,您也可以使用 Navigator.pop

GestureDetector(
  onTap: () {
    final user = userList[index];
    Navigator.pop(context, user);
  },

并在 MyHomePage

上接收数据
onPressed: () async {
//....
final data = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const ViewUser(),
  ),
);
if (data != null) {
  nameController.text = data.name ?? "";
  ageController.text = data.age.toString();
}

更多关于 navigate-with-arguments