Flutter - 如何在传递值的同时从子项更改父项的主体小部件?

Flutter - How to change the body widget of parent, while passing a value, from child?

所以,我有一个“主页”页面,它有脚手架、应用栏、主体和底部导航栏。 正文作为小部件从列表中加载,具体取决于在 bottomNavigationBar 上单击的内容。 我希望能够在当前加载到父主体中的子部件中按下某些东西,并将父部件的主体部件更改为另一个子部件,同时也将值传递给子部件。 可以把它想象成在浏览器的 iframe 中按下 link,只是 iframe 改变了,你可以传递一个像 ?id=12.

这样的值

这是“主页”页面:

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedIndex = 0;
  final List<Widget> _children = [
    Page1(),
    Page2(),
    Page3(),
    Page4()
  ];
  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
              actions: <Widget>[
                TextButton(
                  onPressed: () {},
                  child: Text("Log Out", style: TextStyle(color: Colors.white)),
                ),
              ],
              backgroundColor: Colors.blue.shade900,
            ),
      body: _children[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
              items: const <BottomNavigationBarItem>[
                BottomNavigationBarItem(
                  icon: Icon(Icons.work),
                  label: 'Page 1',
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.inventory),
                  label: 'Page 2',
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.alt_route),
                  label: 'Page 3',
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.article),
                  label: 'Page 4',
                ),
              ],
              currentIndex: _selectedIndex,
              onTap: _onItemTapped,
              type: BottomNavigationBarType.fixed,
            ),
    );
  }
}

这是将由 _children[_selectedIndex] 通过按下 bottomNavigationBar

中的按钮之一定义的子窗口小部件
class Page1 extends StatefulWidget {
  @override
  _Page1State createState() => _Page1State();
}

class _Page1State extends State<Page1> {

  @override
  Widget build(BuildContext context) {
    return Text("Click Here",onPressed:(){
    //objective here is to open Page5 in the body of HomePage(not in _children list of homepage, and pass it some value (ie. id 12))
            },
        ),
    );
  }
}

为了举例说明期望,这是我想要在 Page5 中的内容(应该加载到主页的正文中

class Page5 extends StatefulWidget {
  @override
  _Page5State createState() => _Page5State();
}

class _Page5State extends State<Page5> {
  int _variableFromPage1;
  @override
  Widget build(BuildContext context) {
    return Text(_variableFromPage1);
  }
}

任何人都可以建议最好的方法吗?

你这样试试

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

class MyApp extends StatefulWidget {
  // This widget is the root of your application.
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _selectedIndex = 0;
  final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
  Route<dynamic> generateRoute(RouteSettings settings) {
    switch (settings.name) {
        case "Home":
        return MaterialPageRoute(builder: (context) => Home());
      
      case "Settings":
          return MaterialPageRoute(builder: (context) => Settings());
     
      default:
         return MaterialPageRoute(builder: (context) => Default());
     
    }
  }

  void _onItemTapped(int index) {
    switch (index) {
      case 1:
        _navigatorKey.currentState!
            .pushNamedAndRemoveUntil("Home", (route) => false);
        break;
      case 2:
        _navigatorKey.currentState!
            .pushNamedAndRemoveUntil("Settings", (route) => false);
        break;
      default:
        _navigatorKey.currentState!
            .pushNamedAndRemoveUntil("Default", (route) => false);
    }
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Navigator(key: _navigatorKey, onGenerateRoute: generateRoute),
        bottomNavigationBar: BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          items: <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: 'Home',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.settings),
              label: 'Setting',
            ),
          ],
          showSelectedLabels: true,
          showUnselectedLabels: false,
          currentIndex: _selectedIndex,
          selectedItemColor: Colors.white,
          unselectedItemColor: Color(0xFF9e9e9e),
          iconSize: 16,
          backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
          onTap: _onItemTapped,
        ),
      ),
    );
  }
}

您可以像下面的代码示例一样定义自定义回调函数。

class HomePage extends StatefulWidget {      
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedIndex = 0;
  int _selectedID = 0;

  List<Widget> _children;

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

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

    _children = [
      Page1(
        callback: (value) {
          setState(() {
            _selectedID = value;
          });
        },
      ),
      Page2(),
    ];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: (_selectedIndex == 0 && _selectedID > 0)
          ? Page5(id: _selectedID)
          : _children[_selectedIndex],
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.work),
            label: 'Page 1',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.inventory),
            label: 'Page 2',
          ),
        ],
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
        type: BottomNavigationBarType.fixed,
      ),
    );
  }
}

typedef IntCallback(int value);

class Page1 extends StatelessWidget {
  Page1({Key key, @required this.callback}) : super(key: key);

  final IntCallback callback;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: InkWell(
        onTap: () {
          callback(12);
        },
        child: Text("Page1 ::: id >>> 12"),
      ),
    );
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text("Page2"),
    );
  }
}

class Page5 extends StatelessWidget {
  Page5({Key key, @required this.id}) : super(key: key);
  
  final int id;

  @override
  Widget build(BuildContext context) {
    return Center(child: Text("Page5 ::: id $id"));
  }
}