Home > Software engineering >  Call a method from one statefulWidget in tab page in Flutter
Call a method from one statefulWidget in tab page in Flutter

Time:01-07

I have two widgets - one is the main page with tabs and buttons and the second one is - Page with some TextFields. I would like to clean all TextFields after the button click. I tried to use GlobalKey<_Page1> _key = GlobalKey<_Page1>(); and _key.currentState!.CleanAll(); but I received an error - Unhandled Exception: Null check operator used on a null value

Do you have any other ideas on how to do this?

class MyTabs extends StatefulWidget {
  const MyTabs({Key? key}) : super(key: key);

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

class _MyTabsState extends State<MyTabs> {

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        DefaultTabController(
          length: 1, // length of tabs
          initialIndex: 0,
          child: Column(
            children: <Widget>[
              const TabBar(
                labelColor: Colors.green,
                unselectedLabelColor: Colors.blueGrey,
                tabs: [
                  Tab(text: 'Page 1'),
                ],
              ),
              SizedBox(
                height: 200,
                child: TabBarView(
                    children: <Widget>[
                      Page1(),
                    ]
                ),
              ),
            ],
          ),),

        ElevatedButton(
            onPressed: () {
              // <- clean all TextField in Page1
            },
            child: Text('Clean')
        ),
      ],
    );
  }
}

class Page1 extends StatefulWidget {
  const Page1({Key? key}) : super(key: key);

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

class _Page1State extends State<Page1> {

  TextEditingController text1 = TextEditingController();
  TextEditingController text2 = TextEditingController();

  void CleanAll() {
    text1.clear();
    text2.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
      TextField(
        controller: text1,
      ),
        TextField(
          controller: text2,
        ),
      ],
    );
  }
}

CodePudding user response:

You can use a ValueNotifier that will listen on Page1. then we will override initState on Page1 and clear the controlles.

class _MyTabsState extends State<MyTabs> {
  final ValueNotifier<bool> clearNotifier = ValueNotifier(false);

pass it to the Page1

Page1(
  clearCallback: clearNotifier,
),

to notify the listener we are just switching the value. bool value does not matter, we just need to update it.

onPressed: () {
  clearNotifier.value = !clearNotifier.value;
},

and on Page1

class Page1 extends StatefulWidget {
  final ValueNotifier clearCallback;
  const Page1({Key? key, required this.clearCallback}) : super(key: key);

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

class _Page1State extends State<Page1> {
  @override
  void initState() {
    super.initState();
    widget.clearCallback.addListener(() {
      CleanAll();
    });
  }

Test snippet

class MyTabs extends StatefulWidget {
  const MyTabs({Key? key}) : super(key: key);

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

class _MyTabsState extends State<MyTabs> {
  final ValueNotifier<bool> clearNotifier = ValueNotifier(false);
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        DefaultTabController(
          length: 1, // length of tabs
          initialIndex: 0,
          child: Column(
            children: <Widget>[
              const TabBar(
                labelColor: Colors.green,
                unselectedLabelColor: Colors.blueGrey,
                tabs: [
                  Tab(text: 'Page 1'),
                ],
              ),
              SizedBox(
                height: 200,
                child: TabBarView(children: <Widget>[
                  Page1(
                    clearCallback: clearNotifier,
                  ),
                ]),
              ),
            ],
          ),
        ),
        ElevatedButton(
            onPressed: () {
              clearNotifier.value = !clearNotifier.value;
            },
            child: Text('Clean')),
      ],
    );
  }
}

class Page1 extends StatefulWidget {
  final ValueNotifier clearCallback;
  const Page1({Key? key, required this.clearCallback}) : super(key: key);

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

class _Page1State extends State<Page1> {
  @override
  void initState() {
    super.initState();
    widget.clearCallback.addListener(() {
      CleanAll();
    });
  }

  TextEditingController text1 = TextEditingController();
  TextEditingController text2 = TextEditingController();

  void CleanAll() {
    text1.clear();
    text2.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        TextField(
          controller: text1,
        ),
        TextField(
          controller: text2,
        ),
      ],
    );
  }
}

  • Related