Khaled Alkasadi
Khaled Alkasadi

Reputation: 27

send data from widget to another widget in flutter

I want to send data from widget to another widget, in my example i want to send some filter data from FilterScreen.dart to ShopScreen.dart it works fine but i dont know is what i'm doing is correct?

in filter model file:

class FilterData with ChangeNotifier {
  bool isFreeShipping;
  bool isSomeThingElse;

  FilterData({this.isFreeShipping = false, this.isSomeThingElse = false});

  void setFreeShippingValue(bool newval) {
    isFreeShipping = newval;
    notifyListeners();
  }

  void setSomeThingElseValue(bool newval) {
    isSomeThingElse = newval;
    notifyListeners();
  }
}

in main.dart:

return ChangeNotifierProvider(
      create: (context) => FilterData(),
      child: MaterialApp(
       .........
    )
);

in tabs screen:

class TabsScreen extends StatefulWidget {
  @override
  _TabsScreenState createState() => _TabsScreenState();
}

class _TabsScreenState extends State<TabsScreen> {
  List<Map<String, Object>> _pages;
  int _selectedPageIndex = 0;

  @override
  void initState() {
    _pages = [
      {
        'page': ShopScreen(),
        'title': 'shop',
      },
      {
        'page': FilterScreen(),
        'title': 'filter',
      },
    ];
    super.initState();
  }

  void _selectPage(int index) {
    setState(() {
      _selectedPageIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(_pages[_selectedPageIndex]['title']),
      ),
      drawer: DrawerApp(),
      body: _pages[_selectedPageIndex]['page'],
      bottomNavigationBar: BottomNavigationBar(
        onTap: _selectPage,
        backgroundColor: Theme.of(context).primaryColor,
        unselectedItemColor: Colors.white,
        selectedItemColor: Theme.of(context).accentColor,
        currentIndex: _selectedPageIndex,
        // type: BottomNavigationBarType.fixed,
        items: [
          BottomNavigationBarItem(
            backgroundColor: Theme.of(context).primaryColor,
            icon: Icon(Icons.shop),
            title: Text('Shop'),
          ),
          BottomNavigationBarItem(
            backgroundColor: Theme.of(context).primaryColor,
            icon: Icon(Icons.search),
            title: Text('Filter'),
          ),
        ],
      ),
    );
  }
}

in FilterScreen.dart:

class FilterScreen extends StatefulWidget {
  @override
  _FilterScreenState createState() => _FilterScreenState();
}

class _FilterScreenState extends State<FilterScreen> {
  @override
  Widget build(BuildContext context) {
    final data = Provider.of<FilterData>(context);

    return Container(
      child: Center(
        child: Expanded(
          child: ListView(
            children: <Widget>[
              SwitchListTile(
                  title: Text('Free Shipping'),
                  value: data.isFreeShipping,
                  subtitle: Text('get free shipping products'),
                  onChanged: (newValue) {
                    data.setFreeShippingValue(newValue);
                  }),
              SwitchListTile(
                  title: Text('Some thing else'),
                  value: data.isSomeThingElse,
                  subtitle: Text('get filtred products'),
                  onChanged: (newValue) {
                    data.setSomeThingElseValue(newValue);
                  }),
            ],
          ),
        ),
      ),
    );
  }
}

in ShopScreen.dart:

class ShopScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final data = Provider.of<FilterData>(context);

    return Container(
      child: Center(
        child: Text(
            data.isFreeShipping ? 'get favorite Products' : 'get all products'),
      ),
    );
  }
}

enter image description here

Upvotes: 0

Views: 1097

Answers (1)

Alok
Alok

Reputation: 8978

Your question indeed is a pain for most of the developers, which is like I don't know how it works!

So, if you are not able to understand. there are two reasons to that:

  • You just blindly followed the tutorial or documentation, because of the time constraints
  • You did not understand how Flutter Provider State Management works. So, for that, do read upon these:

So, now let us jump to the code. How your code works?

There are multiple things which are responsible for this:

1. Provider Wrap: If you closely look into the main.dart code, you have done this

return ChangeNotifierProvider(
      create: (context) => FilterData(), // here you define the ChangeNotifier class
      child: MaterialApp(
       .........
    )
);

Now looking at the above code, you see, whenever you wrap the app with the ChangeNotifierProvider(), it always rebuilds whenever there is a state change in the class which you have provided inside that, in this case FilterData(). Any changes happens will reflect in the whole app, because ChangeNotifierProvider(), is keep rebuilding the state of the immediate child, in this case your, MaterialApp(), which is wrapped.

2. NotifyChanges from the ChangeNotifier class: If you look at your FilterData, it is the one which is responsible for the rebuilding of the app, which is wrapped by the ChangeNotifierProvider().

Let us see how:

  void setFreeShippingValue(bool newval) {
    isFreeShipping = newval;
    notifyListeners();
  }

  void setSomeThingElseValue(bool newval) {
    isSomeThingElse = newval;
    notifyListeners();
  }

If you closely take a look at the methods, which I mentioned in the above code from your FilterData class only, they have notifyListeners(). These are the ones, which is responsible, whenever your two methods called, it notifies the ChangeNotifierListener to rebuild the widget, and hence you see the updated data every time, you use any of the two methods

3. Using NotifyListeneres method from the FilterData in FilterScreen: So, again if we look closely at the thing which we have mentioned in the point 2, we see that, the method method should be called to make changes in the App which is the immediate child of ChangeNotifierProvider()

                 SwitchListTile(
                  title: Text('Free Shipping'),
                  value: data.isFreeShipping,
                  subtitle: Text('get free shipping products'),
                  onChanged: (newValue) {
                    data.setFreeShippingValue(newValue);
                  }),
              SwitchListTile(
                  title: Text('Some thing else'),
                  value: data.isSomeThingElse,
                  subtitle: Text('get filtred products'),
                  onChanged: (newValue) {
                    data.setSomeThingElseValue(newValue);
                  }),

So, when you call any of the methods in your onChanged, it straight away notifies the Provider that, the value has been changed, and the app rebuilds, and when you switch to the other tab, you see updated result like magic.

MOST IMPORTANT: Your final data = Provider.of<FilterData>(context);, is an instance of the Provider class, which trigger the method to help notify the ChangeNotifierProvider() to make changes in the app

So the mapping is like that:

                                                          Listens to the change
FilterData {setFreeShippingValue, setSomeThingElseValue} <----------------------> ChangeNotifierProvider() REBUILDS MATERIALAPP()

Upvotes: 1

Related Questions