将数据传递给StatefulWidget并在其状态中访问它在Flutter中。

348
我的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


4
可能是传递数据给有状态小部件的重复问题。 - Herohtar
我们如何在_RecordPageState类的函数中使用'recordObject'变量的值? - Kamlesh
2
这个回答解决了你的问题吗?不使用构造函数将StatefulWidget数据传递给State类 - Blasanka
8个回答

511

要在_RecordPageState中使用recordObject,只需像下面这样编写widget.objectname

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

14
对于那些刚接触Flutter的人,请不要忘记像这样定义widget:'@override RecordPage get widget => super.widget;' - hhk
36
为什么这是必要的? - Herohtar
7
recordObject 应该作为 State 类的一部分,这样符合逻辑(内聚性)。把它放在 StatefulWidget 中是不正确的。此外,StatefulWidget 的所有字段都应该是不可变的。如果想要更改 recordObject 引用,怎么办? - Alex Semeniuk
2
不再需要像@hhk的评论中那样定义小部件。 - Filippos Zofakis
1
如果我想在运行时更改RecordPage中的字段怎么办?将该字段作为构造函数参数传递给State类是否是更好的方法? - NM Naufaldo
显示剩余2条评论

125

完整示例

您无需通过构造函数传递参数来使用 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")));

3
很多年前就在这里提到了。在撰写答案之前,请阅读其他回答。 - iDecode
9
如果我需要改变它的值,该怎么办? - Gilian

52
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
请解释为什么这是一个有状态小部件。 - atilkan
1
@atilkan 因为 OP 的初始脚本是 StatefulWidget,他只是添加了一些代码来满足需求。 - adadion
4
我认为在 StateStatefulWidget 类中都拥有 recordObject 字段并不是一个好主意(尽管我看到有一些教程确实这样做)。通过使用 State 类中的 widget 字段访问 StatefulWidget 的字段似乎是更正确的方法(尽管它也有自己的问题)。 - Alex Semeniuk

14

以下是例子:

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 
  }

    

谢谢!我正在寻找在第二页可以修改值的位置。 - Obot Ernest

7

为此,您无需在状态类中创建任何新对象或变量,只需在有状态的类中定义一个finalnullable变量即可。

您可以通过widget.像这样访问此变量:widget.recordObject

class RecordPage extends StatefulWidget {
   final Record? recordObject;
   RecordPage({required this.recordObject});
   @override
   _RecordPageState createState() => new _RecordPageState();
}

class _RecordPageState extends State<RecordPage> {
   @override
   Widget build(BuildContext context) {
      return Text(
         widget.recordObject == null? "the object is null" : "the object isn't null",
   );
 }
}

4

我需要在列表页面中导航回任意一个屏幕,但是当我这样做时,我的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;
            });
          },

0
在我的应用程序中,通常我会使用主要的ChangeNotifierProvider<T>和一些模型类,而不是使用有状态的小部件。
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>();

在我的无状态小部件中。我认为这比有状态小部件更能精确控制运行时状态更改后的重建。

这个方法可以在官方文档中找到,这个概念被称为“将状态提升”。


0

你应该使用发布/订阅机制。 在许多情况和语言中,我更喜欢使用 Rx。对于 Dart/Flutter,这是一个包:https://pub.dev/packages/rxdart

例如,你可以使用BehaviorSubjectwidget A发出数据,将流传递给widget B,后者监听更改并在setState内应用它们。

Widget A:

// initialize subject and put it into the Widget B
BehaviorSubject<LiveOutput> subject = BehaviorSubject();
late WidgetB widgetB = WidgetB(deviceOutput: subject);

// when you have to emit new data
subject.add(deviceOutput);

小部件 B:

// add stream at class level
class WidgetB extends StatefulWidget {
   final ValueStream<LiveOutput> deviceOutput;
   const WidgetB({Key? key, required this.deviceOutput}) : super(key: key);

   @override
   State<WidgetB> createState() => _WidgetBState();
}

// listen for changes
@override
void initState() {
   super.initState();

   widget.deviceOutput.listen((event) {
      print("new live output");
      setState(() {
         // do whatever you want
      });
   });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接