18

I was working with bottom navigation with similar child widgets in which only parameters are changed. The problem only happens when widgets are of StatefulWidget else there is no problem, indications in bottomnavbar is changing but not the body.

Child 1: enter image description here

Child 2: enter image description here

Actual result: enter image description here

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;

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

class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
Widget body;
@override
void initState() {
//    body = getBody(0);
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
  appBar: AppBar(
    title: Text(widget.title),
    elevation: 0,
  ),
  body: body,
  bottomNavigationBar: BottomNavigationBar(
    currentIndex: _counter,
    onTap: (index){
      _counter = index;
      setState(() {
        body = getBody(index);
      });
    },items: [
    BottomNavigationBarItem(icon: Icon(Icons.language),title: 
 Text('HELLO')),
    BottomNavigationBarItem(icon: Icon(Icons.security),title: 
Text('BYE'))
  ]),
 );
}
Widget getBody(int pos){
if(pos==0){
//      return new Mx(category: 'ALPHA',type: '@',);
  return new MyTAbs(category: 'ALPHA',type: '@',);
}
else{
//      return new Mx(category:'BETA',type: '#',);
  return new MyTAbs(category:'BETA',type: '#',);
  }
 }
}
class Mx extends StatelessWidget{
final String type,category;
Mx({this.type,this.category});
@override
Widget build(BuildContext context) {
 return new Scaffold(
  backgroundColor: getColor(),
  body: new Center(
    child: Text(category+' '+type),
  ),
 );
}
Color getColor(){
if(category=='ALPHA'){
  return Colors.red;
}
else{
  return Colors.green;
  }
 }
}
class MyTAbs extends StatefulWidget{
final String type,category;
MyTAbs({this.type,this.category});
Tabs createState() => new Tabs(title: category,type: type);
}
class Tabs extends State<MyTAbs>{
final String title,type;
Tabs({this.title,this.type});
@override
Widget build(BuildContext context) {
// TODO: implement build
return new Scaffold(
  backgroundColor: getColor(),
  appBar: AppBar(
    title: Text(title+' '+type),
  ),
);
}
Color getColor(){
if(title=='ALPHA'){
  return Colors.red;
}
else{
  return Colors.green;
  }
 }
}

and I can't use statelessWidget because there's a dynamic tab section inside.

3 Answers 3

34

Solved this issue by adding new Key as parameter and passed a UniqueKey like

return new MyTAbs(category: 'ALPHA',type: '@',key: UniqueKey(),);

MyTAbs class

class MyTAbs extends StatefulWidget{
  final String type,category;
  final Key key;
  MyTAbs({@required this.key,this.type,this.category});
  Tabs createState() => new Tabs(title: category,type: type,key: key);
}

Tabs class

class Tabs extends State<MyTAbs>{
  final String title,type;
  final Key key;
  Tabs({this.title,this.type,@required this.key});
  @override
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      backgroundColor: getColor(),
      appBar: AppBar(
        title: Text(title+' '+type),
      ),
    );
  }
  Color getColor(){
    if(title=='ALPHA'){
      return Colors.red;
    }
    else{
      return Colors.green;
    }
  }
}

little about Key

You can use keys to control which widgets the framework matches up with other widgets when a widget rebuilds. By default, the framework matches widgets in the current and previous build according to their runtimeType and the order in which they appear. With keys, the framework requires that the two widgets have the same key as well as the same runtimeType. more in flutter docs

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot, stuck today with the same problem. I thought, if one of parameters has been changed, the Widget will be rebuilt, but not, initState() has not been called. UniqKey() worked fine!
1

Change your Tabs class

class Tabs extends State<MyTAbs> {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      backgroundColor: getColor(),
      appBar: AppBar(
        title: Text(widget.category + ' ' + widget.type),
      ),
    );
  }

  Color getColor() {
    if (widget.category == 'ALPHA') {
      return Colors.red;
    } else {
      return Colors.green;
    }
  }
}

Class State (Tabs) created only once. So after that you can't call constructor with new parameters. But you have access to the widgets' fields

Comments

1

your problem in "MyTAbs" passing parameters class

after edit it , now its work

you dont need to pass the date from "Stateful" class to the "State", just call it with "widget.parameterName" in the state your code after edit :

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  Widget body;
  @override
  void initState() {
//    body = getBody(0);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        elevation: 0,
      ),
      body: body,
      bottomNavigationBar: BottomNavigationBar(
          currentIndex: _counter,
          onTap: (index){
            _counter = index;
            setState(() {
              body = getBody(index);
            });
          },items: [
        BottomNavigationBarItem(icon: Icon(Icons.language),title:
        Text('HELLO')),
        BottomNavigationBarItem(icon: Icon(Icons.security),title:
        Text('BYE'))
      ]),
    );
  }
  Widget getBody(int pos){
    if(pos==0){
//      return new Mx(category: 'ALPHA',type: '@',);
      return new MyTAbs(category: 'ALPHA',type: '@',);
    }
    else{

//      return new Mx(category:'BETA',type: '#',);
      return new MyTAbs(category:'BETA',type: '#',);
    }
  }
}
class Mx extends StatelessWidget{
  final String type,category;
  Mx({this.type,this.category});
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      backgroundColor: getColor(),
      body: new Center(
        child: Text(category+' '+type),
      ),
    );
  }
  Color getColor(){
    if(category=='ALPHA'){
      return Colors.red;
    }
    else{
      return Colors.green;
    }
  }
}
class MyTAbs extends StatefulWidget{
  final String type,category;
  MyTAbs({this.type,this.category});
  Tabs createState() => new Tabs();
}
class Tabs extends State<MyTAbs>{


  @override
  Widget build(BuildContext context) {
    print(widget.type);
// TODO: implement build
    return new Scaffold(
      backgroundColor: getColor(),
      appBar: AppBar(
        title: Text(widget.category+' '+widget.type),
      ),
    );
  }
  Color getColor(){
    if(widget.category=='ALPHA'){
      return Colors.red;
    }
    else{
      return Colors.green;
    }
  }
}

1 Comment

thanks @abdalmonem your answer is correct but in my case I'm loading tabs inside Tabs class so can't use yours instead i added a key as parameter as mentioned above. Your answer is a new info for me.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.