【问题标题】:Passing data to StatefulWidget and accessing it in it's state in Flutter将数据传递给 StatefulWidget 并在 Flutter 中以它的状态访问它
【发布时间】:2018-10-21 14:46:22
【问题描述】:

我的 Flutter 应用中有两个屏幕:一个记录列表和一个用于创建和编辑记录的屏幕。

如果我将一个对象传递到第二个屏幕,这意味着我要编辑它,如果我传递 null,则意味着我正在创建一个新项目。编辑屏幕是一个有状态的小部件,我不确定如何在我的情况下使用这种方法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) {
   //.....
  }
}

如何访问 _RecordPageState 内的 recordObject

【问题讨论】:

标签: flutter dart statefulwidget pass-data


【解决方案1】:

要在 _RecordPageState 中使用 recordObject,您只需编写 widget.objectname 如下所示

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

【讨论】:

  • Flutter 新手不要忘记定义 '@override RecordPage get widget => super.widget;'这样的小部件
  • @hhk 为什么有必要这样做?
  • 不应该recordObjectState 类的一部分吗?从逻辑上讲,将它放在StatefulWidget 中是不正确的(就凝聚力而言)。此外,StatefulWidget 的所有字段都应该是不可变的 - 如果您想更改 recordObject 引用怎么办?
  • 我们如何在 _RecordPageState 类的函数中使用 'recordObject' 变量值?
  • 似乎没有必要再像@hhk 的评论那样定义小部件了。
【解决方案2】:

完整示例

您不需要使用它的构造函数将参数传递给 State。 您可以使用 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")));

【讨论】:

  • 这在很多年前here 已经提到过了。在写你的答案之前,请阅读其他答案。
  • 如果我需要改变它的值怎么办?
【解决方案3】:
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
   //.....
  }
}

【讨论】:

  • 请解释为什么这是一个有状态的小部件。
  • @atilkan 因为 OP 初始脚本是一个 StatefulWidget,他只是添加了一些行来满足需求。
  • 我不认为在StateStatefulWidget 类中都有recordObject 字段是一个好主意(即使我看到教程就是这样做的)。使用State 类的widget 字段访问StatefulWidget 字段的方法似乎是一种更正确的方法(尽管它有自己的问题)
【解决方案4】:

通常,您不仅要导航到新屏幕,还要将数据传递到屏幕。例如,您可能想要传递有关被点击的项目的信息。

在本例中,创建一个待办事项列表。点击待办事项时,导航到显示有关记录的信息的新屏幕(小部件)。此配方使用以下步骤:

  • 定义一个 RecordObject 类。
  • 创建一个StatefulWidget。我们称之为 RecordsScreen(用于:显示记录列表)。
  • 创建一个可以显示记录信息的详细信息屏幕。
  • 导航并将数据传递到详细信息屏幕。

定义一个 RecordObject 类

class RecordsScreen extends StatefulWidget {
  List<RecordObject> records;
  RecordsScreen({Key key, @required this.records}) : super(key: key);
  @override
  _RecordsScreenState createState() => _RecordsScreenState();
}

class _RecordsScreenState extends State<RecordsScreen> {
  
  @override
  Widget build(BuildContext context) {
    widget.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:  widget.records.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text( widget.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:  widget.records[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
    

创建详细信息屏幕 - 屏幕标题包含记录的标题,屏幕正文显示描述。

class DetailScreen extends StatefulWidget {
  // 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
  _DetailScreenState createState() => _DetailScreenState();
}

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

【讨论】:

  • 这是一个无状态小部件,该问题的作者专门询问了将变量传递给有状态小部件的状态。
  • 抱歉,现在这个答案在 statefulwidget 中。
【解决方案5】:

我必须导航回列表页面中的任何一个屏幕,但是当我这样做时,我的 onTap 功能停止工作并且导航停止。

class MyBar extends StatefulWidget {
  MyBar({this.pageNumber});
  final pageNumber;
  static const String id = 'mybar_screen';
  @override
  _MyBarState createState() => _MyBarState();
}

class _MyBarState extends State<MyBar> {
  final List pages = [
    NotificationScreen(),
    AppointmentScreen(),
    RequestBloodScreen(),
    ProfileScreen(),
  ];
  @override
  Widget build(BuildContext context) {
    var _selectedItemIndex = widget.pageNumber;
    return Scaffold(
        bottomNavigationBar: BottomNavigationBar(
          elevation: 0,
          backgroundColor: Colors.white,
          unselectedItemColor: Colors.grey.shade700,
          selectedItemColor: Color(kAppColor),
          selectedIconTheme: IconThemeData(color: Color(kAppColor)),
          currentIndex: _selectedItemIndex,
          type: BottomNavigationBarType.fixed,
          onTap: (int index) {
            setState(() {
              _selectedItemIndex = index;
            });
          },

【讨论】:

    【解决方案6】:

    示例如下:

    class nhaphangle extends StatefulWidget {
      final String username;
      final List<String> dshangle;// = ["1","2"];
      const nhaphangle({ Key key, @required this.username,@required this.dshangle }) : super(key: key);
    
    
      @override
      _nhaphangleState createState() => _nhaphangleState();
    }
    
    class _nhaphangleState extends State<nhaphangle> {
      TextEditingController mspController = TextEditingController();
      TextEditingController soluongController = TextEditingController();
      final scrollDirection = Axis.vertical;
      DateTime Ngaysx  = DateTime.now();
      ScrollController _scrollController = new ScrollController();
    
      ApiService _apiService;
      List<String> titles = [];
    
      @override
      void initState() {
        super.initState();
        _apiService = ApiService();
        titles = widget.dshangle;  //here var is call and set to 
      }
    
        
    

    【讨论】:

    • 谢谢!我正在寻找可以修改第二页上的值的位置。
    【解决方案7】:

    在我的应用程序中,我通常不使用有状态的小部件,而是主要在 main.dart 中使用 ChangeNotifierProvider&lt;T&gt;,一些模型类

    class FooModel extends ChangeNotifier {
    
    var _foo = false;
    
    void changeFooState() {
       _foo = true;
       notifyListeners();
    }
    
    bool getFoo () => _foo;
    
    }
    

    var foo = context.read<FooModel>();
    # or
    var foo = context.watch<FooModel>();
    

    在我的无状态小部件中。与有状态的小部件相比,IMO 这让我可以更精确地控制运行时状态更改时的重建。

    配方可以在官方docs找到,这个概念叫做“提升状态”。

    【讨论】:

      猜你喜欢
      • 2019-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多