【问题标题】:Nullable class instance with Provider带有 Provider 的可空类实例
【发布时间】:2022-01-08 16:25:10
【问题描述】:

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

用户模型

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 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. user 对象实例添加到 UserList 列表中
  4. 使用provider 提供该列表。(Provider.of&lt;UserList&gt;(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 包裹,以便能够获得功能。我希望到目前为止一切都清楚。 问题是; 当我点击每个项目时,我想返回first page。但是,这次TextField 不应该为空。它必须替换为该项目的值。例如。如果我点击John Nash43。第一个页面必须弹出该列表项的字段值。为了能够做到这一点,我使用另一个Provider 来提供User 对象。但是,由于 null 安全性,我无法做到这一点,它给出了有关用户对象为 null 的错误。有什么有用的想法吗?

第二页

第二页代码

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()),
                        ],
                      ),
                    ),
                  ),
                ),
              ],
            );
          }),
    );
  }
}

【问题讨论】:

    标签: flutter dart flutter-provider dart-null-safety


    【解决方案1】:

    当您使用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

    【讨论】:

    • 非常感谢我一直在寻找这个答案一周
    • 也可以使用constructor,可以查看this
    • 谢谢,但是当我实现构造函数时,我每次都必须提供一个用户对象。
    • 您可以使用可为空的用户并检查构建时间,就像我在参数上所做的那样
    • 我想问这个问题。我在第一页得到数据。但是现在,当我编辑文本字段并保存它时,它会在第二页上创建一个新的列表项。这不是我想要的。我想覆盖第二页上的项目。我想不出办法。你能帮我解决这个问题吗?
    猜你喜欢
    • 2018-10-25
    • 1970-01-01
    • 2021-09-02
    • 1970-01-01
    • 2018-02-17
    • 2017-05-29
    • 2012-11-28
    • 2022-06-23
    • 1970-01-01
    相关资源
    最近更新 更多