Flutter PageView页面间无跳转数据传递及页面切换实现
Flutter PageView 页面间数据传递解决方案
需求说明
需要在PageView组件内实现页面间数据传递,无需跳转新页面:在page页面的弹窗输入用户名并点击OK后,滑动切换到codeforce页面,同时将用户名传递过去展示。当前使用Navigator.push()会替换屏幕,不符合需求。
解决方案
核心思路是状态提升,把需要共享的用户名数据存放在PageView的父组件(HomeScreen)的状态中,子页面通过回调更新父组件状态,目标页面直接使用父组件的状态值。
实现步骤
- 在HomeScreen的状态类中添加存储用户名的变量
- 给page组件添加回调函数,用于传递输入的用户名
- 修改codeforce组件,接收父组件传递的用户名并展示
- 调整page页面弹窗OK按钮的逻辑,调用回调更新状态后切换页面
修改后的代码
HomeScreen代码
class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @override State<Home> createState() => _HomeState(); } class _HomeState extends State<Home> { final PageController _controller = PageController(); int _index = 0; // 存储CodeForces用户名 String _cfUsername = ""; @override Widget build(BuildContext context) { return Scaffold( body: PageView( controller: _controller, children: [ Page( controller: _controller, onUsernameSubmitted: (username) { setState(() { _cfUsername = username; }); }, ), const Codechef(), Codeforce(sub: _cfUsername), ], onPageChanged: (page) { setState(() { _index = page; }); }, ), bottomNavigationBar: Container( color: const Color.fromARGB(255, 19, 63, 99), child: Padding( padding: const EdgeInsets.all(8), child: GNav( tabs: const [ GButton( icon: Icons.home, text: "Home", ), GButton( icon: Cp.codechef_svgrepo_com, text: "CodeChef", ), GButton( icon: Cp.codeforces_svgrepo_com, text: "CodeForces", ) ], onTabChange: (index) { setState(() { _index = index; }); _controller.jumpToPage(index); }, color: Colors.green, backgroundColor: const Color.fromARGB(255, 22, 64, 98), activeColor: Colors.white, tabBackgroundColor: const Color.fromARGB(255, 18, 44, 65), gap: 20, padding: const EdgeInsets.all(20), rippleColor: const Color.fromARGB(255, 51, 23, 23), selectedIndex: _index, ), ), ), ); } }
Page页面代码
import 'package:flutter/material.dart'; class Page extends StatefulWidget { final PageController controller; final Function(String) onUsernameSubmitted; const Page({Key? key, required this.controller, required this.onUsernameSubmitted}) : super(key: key); @override State<Page> createState() => _PageState(); } class _PageState extends State<Page> { final TextEditingController _textFieldController = TextEditingController(); late String _codeDialog; bool _en = false; Future<void> _displayTextInputDialog(BuildContext context) { return showDialog( context: context, builder: (context) { return AlertDialog( backgroundColor: const Color.fromARGB(255, 55, 74, 90), title: const Text( 'UserName', style: TextStyle(color: Colors.white), ), content: TextFormField( onChanged: (value) { setState(() { _codeDialog = value; }); }, controller: _textFieldController, decoration: const InputDecoration( hintText: "Enter a valid user name", hintStyle: TextStyle(color: Colors.white), ), style: const TextStyle( color: Colors.white, ), validator: (value) { if (value == null || value.isEmpty) { return "Enter User name"; } return null; }, ), actions: <Widget>[ ElevatedButton( child: const Text( 'CANCEL', style: TextStyle(color: Colors.white), ), onPressed: () { Navigator.pop(context); }, style: ElevatedButton.styleFrom(primary: Colors.red), ), ElevatedButton( child: const Text( 'OK', style: TextStyle(color: Colors.white), ), onPressed: () { setState(() { _en = true; // 调用回调传递用户名 widget.onUsernameSubmitted(_codeDialog); // 跳转到CodeForces页面 widget.controller.jumpToPage(2); }); Navigator.pop(context); }, style: ElevatedButton.styleFrom(primary: Colors.green), ), ], ); }); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(8.0), child: Container( child: Center( child: GridView( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10), children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: const Color.fromARGB(255, 97, 78, 78)), child: Column( children: [ const Icon( Cp.codechef_svgrepo_com, size: 100, ), const Text("CodeChef", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Color.fromARGB(255, 166, 201, 229), )) ], mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.center, ), ), InkWell( onTap: () async { await _displayTextInputDialog(context); }, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: const Color.fromARGB(255, 40, 83, 118)), child: Column( children: [ const Icon( Cp.codeforces_svgrepo_com, size: 100, ), const Text( "CodeForces", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Color.fromARGB(255, 166, 201, 229)), ), _en ? Text(_codeDialog) : const Text("") ], mainAxisAlignment: MainAxisAlignment.center, ), ), ) ], shrinkWrap: true, ), ), ), ); } }
Codeforce页面示例
class Codeforce extends StatelessWidget { final String sub; const Codeforce({Key? key, required this.sub}) : super(key: key); @override Widget build(BuildContext context) { return Center( child: Text( sub.isEmpty ? "请输入用户名" : "CodeForces用户名:$sub", style: const TextStyle(fontSize: 20), ), ); } }
内容的提问来源于stack exchange,提问作者Devansh
相关产品推荐
相关产品推荐

