Sardorek Aminjonov
Sardorek Aminjonov

Reputation: 834

Why my pages are not refreshing with bottom navigation in flutter?

I am working with bottom navigation bar in flutter. I want to refresh every tab when tabs are switched. First I tried to reuse one stateless widget for all the tabs. But it is rerendering pages. My code is as follows:

class _CreateOrderState extends State<CreateOrder> {
  int _currentTabIndex = 0;

  @override
  Widget build(BuildContext context) {
     final _kTabPages = <Widget>[
       FoodCategory(foodCategory: 'nationalFood'),
       FoodCategory(foodCategory: 'fastFood'),
       FoodCategory(foodCategory: 'dessert'),
       FoodCategory(foodCategory: 'drinks'),
     ];

    final _kBottomNavBarItems = <BottomNavigationBarItem>[
      const BottomNavigationBarItem(
        icon: Icon(Icons.fastfood_outlined),
        label: 'Традиционная',
      ),
      const BottomNavigationBarItem(
        icon: Icon(Icons.alarm),
        label: 'Фаст Фуд',
      ),
      const BottomNavigationBarItem(
        icon: Icon(Icons.food_bank_outlined),
        label: 'Дессерты',
      ),
      const BottomNavigationBarItem(
        icon: Icon(Icons.emoji_food_beverage),
        label: 'Напитки',
      ),
    ];
    assert(_kTabPages.length == _kBottomNavBarItems.length);
    final bottomNavBar = BottomNavigationBar(
      items: _kBottomNavBarItems,
      currentIndex: _currentTabIndex,
      type: BottomNavigationBarType.fixed,
      onTap: (int index) {
        setState(() => _currentTabIndex = index);
      },
    );

    return WillPopScope(
      onWillPop: () => _onWillPop(),
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Создание заказа'),
          backgroundColor: Theme.of(context).primaryColor,
          actions: [
            Container(
              child: Stack(
                children: [
                  IconButton(
                    icon: Icon(Icons.shopping_bag_outlined),
                    onPressed: () =>
                        Navigator.pushNamed(context, '/orderReview'),
                    iconSize: 30,
                  ),
                ],
              ),
            )
          ],
        ),
        body: _kTabPages[_currentTabIndex],
        // body: IndexedStack(
        //   index: _currentTabIndex,
        //   children: _kTabPages,
        // ),
        bottomNavigationBar: bottomNavBar,
      ),
    );
  }

This is my stateless widget:


import 'package:counter/blocs/food/food_bloc.dart';
import 'package:counter/data/repository/food_repository.dart';
import 'package:counter/presentation/widgets/Loading.dart';
import 'package:counter/presentation/widgets/MenuItem.dart';
import 'package:counter/presentation/widgets/network_error.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class FoodCategory extends StatelessWidget {
  final String foodCategory;
  FoodCategory({@required this.foodCategory});

  @override
  Widget build(BuildContext context) {
    FoodRepository foodRepository = FoodRepository(category: this.foodCategory);

    return BlocProvider<FoodBloc>(
      create: (BuildContext context) =>
          FoodBloc(foodRepository: foodRepository)..add(FoodLoadEvent()),
      child: Scaffold(
        body: BlocBuilder<FoodBloc, FoodState>(
          builder: (context, state) {
            if (state is FoodInitial) {
              return Text('Initial state');
            }
            if (state is FoodLoadingState) {
              return CustomLoading();
            }
            if (state is FoodLoadedState) {
              return ListView.builder(
                itemBuilder: (BuildContext context, index) {
                  return MenuItem(foodItem: state.loadedFoodItems[index]);
                },
                itemCount: state.loadedFoodItems.length,
              );
            } else {
              return NetworkErrorWidget();
            }
          },
        ),
      ),
    );
  }
}

But when I used different widgets for all the tabs, it has started to work properly and refreshed.

    final _kTabPages = <Widget>[
      NationalFood(foodCategory: 'nationalFood'),
      FastFoodScreen(foodCategory: 'fastFood'),
      DessertsScreen(foodCategory: 'dessert'),
      DrinksScreen(foodCategory: 'drinks'),
    ];

Upvotes: 4

Views: 7248

Answers (3)

I guess this is very late to answer this question. I too faced same kind of problem. Child widgets are not redrawing once the value is changed in parent widget. So I searched for 3 days and finally I found a solution.

  1. Loaded the child widget with Unique Key

  2. Child widgets initialized inside build method.

After this changes, if state changes in parent then the child widget is also getting refreshed.

Thanks

Upvotes: 0

Bach
Bach

Reputation: 3326

Since you are placing the _kTabPages and _kBottomNavBarItems initialization within the build() method, these variables are assigned new values every time there's a change in state (when you change tabs). This is why the tabs keep re-rendering.

To stop this, place your initialization within the initState(). Something like this:

import 'package:flutter/material.dart';
import 'package:test_flutter_app/test.dart';

class CreateOrder extends StatefulWidget {
  @override
  _CreateOrderState createState() => _CreateOrderState();
}

class _CreateOrderState extends State<CreateOrder> {
  int _currentTabIndex = 0;
  List<Widget> _kTabPages;
  List<BottomNavigationBarItem> _kBottomNavBarItems;
  BottomNavigationBar bottomNavBar;

  _updateTabs() {
    _kTabPages = <Widget>[
      FoodCategory(key: UniqueKey(), foodCategory: 'nationalFood'),
      FoodCategory(key: UniqueKey(), foodCategory: 'fastFood'),
      FoodCategory(key: UniqueKey(), foodCategory: 'dessert'),
      FoodCategory(key: UniqueKey(), foodCategory: 'drinks'),
    ];

    _kBottomNavBarItems = <BottomNavigationBarItem>[
      const BottomNavigationBarItem(
        icon: Icon(Icons.fastfood_outlined),
        label: 'Традиционная',
      ),
      const BottomNavigationBarItem(
        icon: Icon(Icons.alarm),
        label: 'Фаст Фуд',
      ),
      const BottomNavigationBarItem(
        icon: Icon(Icons.food_bank_outlined),
        label: 'Дессерты',
      ),
      const BottomNavigationBarItem(
        icon: Icon(Icons.emoji_food_beverage),
        label: 'Напитки',
      ),
    ];
    bottomNavBar = BottomNavigationBar(
      items: _kBottomNavBarItems,
      currentIndex: _currentTabIndex,
      type: BottomNavigationBarType.fixed,
      onTap: (int index) {
        setState(() => _currentTabIndex = index);
      },
    );
    assert(_kTabPages.length == _kBottomNavBarItems.length);
  }

  @override
  void initState() {
    _updateTabs();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => true,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Создание заказа'),
          backgroundColor: Theme.of(context).primaryColor,
        ),
        body: _kTabPages[_currentTabIndex],
        // body: IndexedStack(
        //   index: _currentTabIndex,
        //   children: _kTabPages,
        // ),
        bottomNavigationBar: bottomNavBar,
      ),
    );
  }
}

Upvotes: 0

Huthaifa Muayyad
Huthaifa Muayyad

Reputation: 12373

Inside the initState of your FoodCategory or NationalFood widget, add the function the retrieves your data.

Upvotes: 0

Related Questions