实现 setstat 和绑定变量

Implement setstat and bind variables

我正在尝试从另一个 dart 文件(“int myId”和“String myMenu”)获取并显示 2 个变量值,这些变量随每个“onTap”小部件一起更新,我的代码有效,但仅如果我进行“热重载”,我想我需要在某处放置一个“setstate”,但我很难实现它。

我认为问题出在这里,我的小部件文本 return 对我来说是“空”,但是如果我点击菜单按钮并执行“热重载”,就没问题了。

displayText.dart

import 'package:flutter/material.dart';
import './menu.dart';

class display extends StatefulWidget {
  int myId;
  String myMenu;
  display(this.myId, this.myMenu);
  @override
  _displayState createState() => _displayState();
}

class _displayState extends State<display> {
  Future myVarUsed() async {
    //Each press on the button return the value
    setState(() {
      print('myIdDsiplay: ${widget.myId}'); // null
      print('myMenuDisplay : ${widget.myMenu}'); // null
    });
  }

  @override
  void initState() {
    super.initState();
    myVarUsed();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      height: 250,
      width: 250,
      child: Row(
        children: [
          Text('My ID is : ${widget.myId}'),
          Text('My menu is : ${widget.myMenu}'),
        ],
      ),
    );
  }
}

此文件包含滚动条内的菜单,每个按钮 return ID 和(按钮的)名称并将其存储在我使用的 2 个变量(“int myId”和“String myMenu”)中想通过

menu.dart

import 'package:flutter/material.dart';
import './mylist.dart';
import './displayText.dart';

class Menu extends StatefulWidget {
  static int myId;
  static String myMenu;
  @override
  _MenuState createState() => _MenuState();
}

class _MenuState extends State<Menu> {
  Container scrollList() {
    final PageController controller = PageController(initialPage: 1, keepPage: true, viewportFraction: 0.35);

    return Container(
      color: Colors.red,
      height: 90,
      child: PageView.builder(
        scrollDirection: Axis.horizontal,
        controller: controller,
        itemCount: listdata.length,
        physics: BouncingScrollPhysics(),
        itemBuilder: (BuildContext context, int index) {
          return Container(
            child: gestureDetector_Ontap(index),
          );
        },
      ),
    );
  }

  GestureDetector gestureDetector_Ontap(int index) {
    return GestureDetector(
      onTap: () {
        Menu.myId = listdata[index].id;
        Menu.myMenu = listdata[index].menuObj;
        display(Menu.myId, Menu.myMenu);

        print('myIDMenu ${Menu.myId}');
        print('myMenuMenu ${Menu.myMenu}');
      },

      child: Container(
        alignment: AlignmentDirectional.center,
        child: Text(
          '${listdata[index].menuObj}',
        ),
      ),
    );
  }

  Widget build(BuildContext context) {
    return Container(
      child: scrollList(),
    );
  }
}

此文件包含我的列表和他的 class

mylist.dart

class listModel {
  int id;
  String menuObj;
  listModel(this.id, this.menuObj);
}

List listdata = [
  listModel(0, 'Menu01'),
  listModel(1, 'Menu02'),
  listModel(2, 'Menu03'),
  listModel(3, 'Menu04'),
  listModel(4, 'Menu05')
];

和容器

main.dart

import 'package:flutter/material.dart';
import './menu.dart';
import './displayText.dart';
import './mylist.dart';

void main() {
  runApp(MyHomePage());
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Container(
          child: Column(
            children: <Widget>[
              Menu(),
              display(Menu.myId, Menu.myMenu),
            ],
          ),
        ),
      ),
    );
  }
}

问题

你这样定义Menu

class Menu extends StatefulWidget {
  static int myId;
  static String myMenu;

  @override
  _MenuState createState() => _MenuState();
}

当您的应用程序启动时,myIdmyMenu 是未初始化的变量,因此它们被隐式设置为 null。


_MyHomePageState里面,你调用

display(Menu.myId, Menu.myMenu)

由于您还没有初始化 Menu.myIdMenu.myMenu,它们仍然是空的。


当您点击 GestureDetector 时,您会以这种方式初始化 Menu.myIdMenu.myMenu

Menu.myId = listdata[index].id;
Menu.myMenu = listdata[index].menuObj;
display(Menu.myId, Menu.myMenu);

print('myIDMenu ${Menu.myId}');
print('myMenuMenu ${Menu.myMenu}');

现在,Menu.myIdMenu.myMenu 被定义为非空值。不过这个不会更新Container的display(Menu.myId, Menu.myMenu),所以还是null,需要自己更新。

解决方案

我已经通过代码添加了注释,指出了更好的方法:

import 'package:flutter/material.dart';

// Avoid displaying the warning "Name types using UpperCamelCase."
class Display extends StatefulWidget {
  // Make these fields final and the constructor const
  final int myId;
  final String myMenu;
  
  const Display(this.myId, this.myMenu);
  
  @override
  _DisplayState createState() => _DisplayState();
}

// Avoid displaying the warning "Name types using UpperCamelCase."
class _DisplayState extends State<Display> {
  // You don't need this Future nor this initState
  // 
  // Future myVarUsed() async {
  //   setState(() {
  //     print('myIdDsiplay: ${widget.myId}'); // null
  //     print('myMenuDisplay : ${widget.myMenu}'); // null
  //   });
  //  }
  // 
  // @override
  // void initState() {
  //   super.initState();
  //   myVarUsed();
  // }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
      height: 250,
      width: 250,
      child: Row(
        children: [
          Text('My ID is : ${widget.myId}'),
          Text('My menu is : ${widget.myMenu}'),
        ],
      ),
    );
  }
}

class Menu extends StatefulWidget {
  // Avoid using mutable static fields
  // static int myId;
  // static String myMenu;
  
  // To simplify, you can add a onChanged callback to 
  // be triggered whenever you change `myId` and `myMenu`
  final void Function(int myId, String myMenu) onChanged;
  
  const Menu({this.onChanged});
  
  @override
  _MenuState createState() => _MenuState();
}

class _MenuState extends State<Menu> {
  Container scrollList() {
    final PageController controller = PageController(initialPage: 1, keepPage: true, viewportFraction: 0.35);

    return Container(
      color: Colors.red,
      height: 90,
      child: PageView.builder(
        scrollDirection: Axis.horizontal,
        controller: controller,
        itemCount: listdata.length,
        physics: BouncingScrollPhysics(),
        itemBuilder: (BuildContext context, int index) {
          return Container(
            child: gestureDetectorOntap(index),
          );
        },
      ),
    );
  }

  // Avoid displaying the warning "Name non-constant identifiers using lowerCamelCase."
  GestureDetector gestureDetectorOntap(int index) {
    return GestureDetector(
      onTap: () {
        // Make these local variables
        int myId = listdata[index].id;
        String myMenu = listdata[index].menuObj;
        
        // Call the `onChanged` callback
        widget.onChanged(myId, myMenu);
        
        // This widget is being thrown away
        // display(Menu.myId, Menu.myMenu);

        print('myIDMenu $myId');
        print('myMenuMenu $myMenu');
      },

      child: Container(
        alignment: AlignmentDirectional.center,
        child: Text(
          '${listdata[index].menuObj}',
        ),
      ),
    );
  }

  Widget build(BuildContext context) {
    return Container(
      child: scrollList(),
    );
  }
}

// Avoid the warning "Name types using UpperCamelCase."
class ListModel {
  // You can make these fields final and the constructor const
  final int id;
  final String menuObj;
  
  const ListModel(this.id, this.menuObj);
}

// You can make this list const to avoid modifying it unintentionally later
const List<ListModel> listdata = [
  ListModel(0, 'Menu01'),
  ListModel(1, 'Menu02'),
  ListModel(2, 'Menu03'),
  ListModel(3, 'Menu04'),
  ListModel(4, 'Menu05')
];

void main() {
  runApp(MyHomePage());
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // Create fields to store the current `myId` and current `myMenu`
  int myId;
  String myMenu;
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Container(
          child: Column(
            children: <Widget>[
              // Add the `onChanged` callback here, updating this widget state
              Menu(
                onChanged: (newMyId, newMyMenu) {
                  setState(() {
                    myId = newMyId;
                    myMenu = newMyMenu;
                  });
                }
              ),
              // Access the current values here
              Display(myId, myMenu),
            ],
          ),
        ),
      ),
    );
  }
}