JMain
JMain

Reputation: 365

Using setState in separate BottomNotifcationBar class back to the main class

If I keep the bottomNotificationBar in the same class as the rest of the page, setState works properly and the buttons work properly.

If I move the bottomNotificationBar to another class, I cannot get the setState to work, because it needs to reference back to the main class. I've tried a few things, but I can't wrap my mind around this yet.

The error is: The following assertion was thrown while handling a gesture: setState() called in constructor:

The part that isn't working is marked near the bottom of this:

    import 'package:flutter/material.dart';

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

    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'My Title',
          home: new MyHomePage(),
        );
      }
    }


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


    class _MyHomePageState extends State<MyHomePage> {
      var selectedPageIndex = 0;
      var pages = [ Page1(), Page2(), ];

      @override
      Widget build(BuildContext context) {
        return new Scaffold(
          body: pages[selectedPageIndex],
          bottomNavigationBar:
              MyClass().buildBottomNavigationBar(selectedPageIndex),
        );
      }
    }

    class MyClass {
      BottomNavigationBar buildBottomNavigationBar(selectedPageIndex) {
        return new BottomNavigationBar(
          type: BottomNavigationBarType.fixed,
          items: [
            BottomNavigationBarItem(
              title: Text("Page1"),
              icon: Icon(Icons.account_circle),
            ),
            BottomNavigationBarItem(
              title: Text("Page2"),
              icon: Icon(Icons.account_circle),
            ),
          ],
          onTap: (index) {

/////////////////////////////START OF SECTION///////////////////////////
            _MyHomePageState().setState(() {
              selectedPageIndex = index;
            });
/////////////////////////////END OF SECTION///////////////////////////

          },
          currentIndex: selectedPageIndex,
        );
      }
    }

--------------EDIT:----------------

Ok, now I have the following code below, and I am getting the following 2 things:

info: The member 'setState' can only be used within instance members of subclasses of 'package:flutter/src/widgets/framework.dart'.

exception: The following NoSuchMethodError was thrown while handling a gesture: The method 'setState' was called on null. Receiver: null Tried calling: setState(Closure: () => Null)

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'My Title',
      home: new MyHomePage(),
    );
  }
}


class MyHomePage extends StatefulWidget {

  static void setIndex(BuildContext context, int _newIndex) {
    _MyHomePageState state = context.ancestorStateOfType(TypeMatcher<_MyHomePageState>());
    state.setState(() {
      state.selectedPageIndex =_newIndex;
    });
  }

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


class _MyHomePageState extends State<MyHomePage> {
  var selectedPageIndex = 0;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: new Container(),
      bottomNavigationBar:
          MyClass().buildBottomNavigationBar(context,selectedPageIndex),
    );
  }
}

class MyClass {
  BottomNavigationBar buildBottomNavigationBar(context,selectedPageIndex) {
    return new BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      items: [
        BottomNavigationBarItem(
          title: Text("Page1"),
          icon: Icon(Icons.account_circle),
        ),
        BottomNavigationBarItem(
          title: Text("Page2"),
          icon: Icon(Icons.account_circle),
        ),
      ],
      onTap: (index) {
    MyHomePage.setIndex(context, index);
    },
      currentIndex: selectedPageIndex,
    );
  }
}

Upvotes: 2

Views: 1973

Answers (2)

Mazin Ibrahim
Mazin Ibrahim

Reputation: 7869

You should modify your MyHomePage by adding a static method into it so its state can be called from anywhere:

  class MyHomePage extends StatefulWidget {

  static void setIndex(BuildContext context, int _newIndex) {
  _MyHomePageState state = context.ancestorStateOfType(TypeMatcher<_MyHomePageState>());
    state.setState(() {
      state.selectedPageIndex =_newIndex;
    });
  }

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

Then when you want to change the index call:

  onTap (index) {
    MyHomePage.setIndex(context, index);
  }

Upvotes: 0

anmol.majhail
anmol.majhail

Reputation: 51206

What you Require is CallBAck Function from the other class. As setState has to be called on object -_MyHomePageState.

With Class Constructors we pass the initial Data & got a Callback on SetState().

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'My Title',
      home: new MyHomePage(),
    );
  }
}

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

class _MyHomePageState extends State<MyHomePage> {
  var selectedPageIndex = 0;
  var pages = [
    Page1(),
    Page2(),
  ];

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      body: pages[selectedPageIndex],
      bottomNavigationBar: MyClass(
        selectedPageIndex: selectedPageIndex,
        myFunc: _myFunc,
      ),
    );
  }

  void _myFunc(int index) {
    setState(() {
      selectedPageIndex = index;
    });
  }
}

class MyClass extends StatelessWidget {
  MyClass({this.selectedPageIndex, this.myFunc});
  final int selectedPageIndex;
  final Function myFunc;
  @override
  Widget build(BuildContext context) {
    return BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      items: [
        BottomNavigationBarItem(
          title: Text("Page1"),
          icon: Icon(Icons.account_circle),
        ),
        BottomNavigationBarItem(
          title: Text("Page2"),
          icon: Icon(Icons.account_circle),
        ),
      ],
      onTap: (index) {
/////////////////////////////START OF SECTION///////////////////////////
        myFunc(index);
/////////////////////////////END OF SECTION///////////////////////////
      },
      currentIndex: selectedPageIndex,
    );
  }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        child: Text('1'),
      ),
    );
  }
}

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

Upvotes: 2

Related Questions