I have two tabA
, tabB
and these are switched by user tapping.
What I want to do is
- At first
tabA
opens. tabB
text changes depending ontabA
state.- user opens
tabB
,there comes changed text.
My basic idea is getting the tabB
state via object key.
However there is a problem,
Before opening tabB, state of tabB is not created.
These are my source code tabA
is playerPage
, tabB
is settingPage
class _MainFrameState extends State<MainFrame>{
void _onItemTapped(int index) => setState(() => _selectedIndex = index );
int _selectedIndex = 0;
Widget settingPage = Text("");
Widget playerPage = Text("");
GlobalKey<_PlayerPageState> _playerPageKey = new GlobalKey<_PlayerPageState>();
GlobalKey<_SettingPageState> _settingPageKey = new GlobalKey<_SettingPageState>();
@override
void initState() {
print("Main Frame init state");
super.initState();
playerPage = PlayerPage(key:_playerPageKey);
settingPage = SettingPage(key:_settingPageKey);
}
function whenSomethingChanged(){ //this is called by push button or some user action,so initState() is already called.
print(playerPage.currentState!) // it has state and operatable.
print(settingPage.currentState!) // I want to change the tabB text but it returns null.
}
@override
Widget build(BuildContext context) {
print("Main Frame build");
List<Widget> _pages = [
playerPage,
settingPage
];
return Scaffold(
appBar: EmptyAppBar(),
body:Container(
decoration: new BoxDecoration(color: Colors.red),
child:Center(child:_pages.elementAt(_selectedIndex),)),
bottomNavigationBar: BottomNavigationBar(
selectedItemColor: Color(0xffC03410),
unselectedItemColor: Color(0xffE96D2F),
backgroundColor: Color(0xffF7BF51),
type: BottomNavigationBarType.fixed,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.play_circle),
label: 'Player',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Setting',
),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
);
}
}
I can tell that when first build is called PlayerPage
is created but SettingPage
is not.
However I want to control the SettinPage , before it show.
What is the solution for this problem??
CodePudding user response:
Since your settingPage is not in the tree, you can't really access its state because it was not created.
Whenever you change your _selectedIndex
in the code below, either a new settingPage or a playerPage is inflated, so just create it already with the value it depends on, listening to it if necessary.
body:Container(
decoration: new BoxDecoration(color: Colors.red),
child:Center(child:_pages.elementAt(_selectedIndex),)),
CodePudding user response:
Since you are updating the screen based on the users input in page 1 I have included a code where if the text field is empty it will show a message and if it has value that value is displayed in second page
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MainFrame(),
);
}
}
class MainFrame extends StatefulWidget {
const MainFrame({key});
@override
State<MainFrame> createState() => _MainFrameState();
}
class _MainFrameState extends State<MainFrame> {
void _onItemTapped(int index) => setState(() {
print(playerPageController.text);
_selectedIndex = index;
});
int _selectedIndex = 0;
late TextEditingController playerPageController;
late Widget settingPage;
late Widget playerPage;
late List<Widget> _pages;
@override
void initState() {
playerPageController = TextEditingController();
print("Main Frame init state");
super.initState();
}
@override
Widget build(BuildContext context) {
settingPage = Text((playerPageController.text.isEmpty)
? "Theres no content here"
: playerPageController.text);
playerPage = Center(
child: TextField(
controller: playerPageController,
autofocus: true,
));
_pages = [playerPage, settingPage];
print("Main Frame build");
return Scaffold(
body: Container(
decoration: new BoxDecoration(color: Colors.red),
child: Center(
child: _pages.elementAt(_selectedIndex),
)),
bottomNavigationBar: BottomNavigationBar(
selectedItemColor: Color(0xffC03410),
unselectedItemColor: Color(0xffE96D2F),
backgroundColor: Color(0xffF7BF51),
type: BottomNavigationBarType.fixed,
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.play_circle),
label: 'Player',
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: 'Setting',
),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
);
}
}
CodePudding user response:
Since you didn't tell what kind of state of TabA you want to show on TabB, I will assume it's a String and wrote this. There's a lot of ways of doing what you want to achieve, this is just one of them.
Step 1: Pass the value of PlayerPage state to SettingPage like this:
class SettingPage extends StatefulWidget {
const SettingPage({
Key? key,
required this.text,
}) : super(key: key);
final String text;
@override
_SettingPageState createState() => _SettingPageState();
}
class _SettingPageState extends State<SettingPage> {
@override
Widget build(BuildContext context) {
return Center(child: Text(widget.text));
}
}
Step 2: Let's assume state you want to show on SettingPage is from TextField. Maybe a player name. Then you'll need to pass that textField value to MainFrame() widget whenever it changes.
class PlayerPage extends StatefulWidget {
const PlayerPage({
Key? key,
required this.onTextChanged,
}) : super(key: key);
final Function(String) onTextChanged;
@override
_PlayerPagetate createState() => _PlayerPagetate();
}
class _PlayerPagetate extends State<PlayerPage> {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Center(
child: TextField(
controller: _controller,
onChanged: (value) {
widget.onTextChanged(value);
},
),
);
}
}
Step 3: On MainFrame widget, now you get playerName into _playerName variable from PlayerPlage and pass it into SettingPage like this. Whenever the value changes _playerName will change too:
class _MainFrameState extends State<MainFrame> {
void _onItemTapped(int index) => setState(() => _selectedIndex = index);
int _selectedIndex = 0;
String _playerName = '';
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
print("Main Frame build");
List<Widget> _pages = [
PlayerPage(onTextChanged: (value) {
setState(() {
_playerName = value;
});
}),
SettingPage(text: _playerName)
];
return Scaffold(
// rest of the codes are same.
)