Почему мои страницы не обновляются из-за трепещущей нижней навигации?

Я работаю с нижней панелью навигации в трепете. Я хочу обновлять каждую вкладку при переключении вкладок. Сначала я попытался повторно использовать один виджет без сохранения состояния для всех вкладок. Но это перерисовка страниц. Мой код выглядит следующим образом:

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,
      ),
    );
  }

Это мой виджет без сохранения состояния:


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();
            }
          },
        ),
      ),
    );
  }
}

Но когда я использовал разные виджеты для всех вкладок, он начал работать правильно и обновился.

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

person Sardorek Aminjonov    schedule 04.04.2021    source источник


Ответы (2)


Внутри initState вашего FoodCategory или NationalFood виджета добавьте функцию, которая извлекает ваши данные.

person Huthaifa Muayyad    schedule 04.04.2021
comment
Не влияет ли на производительность, если я конвертирую его в виджет с отслеживанием состояния? - person Sardorek Aminjonov; 05.04.2021
comment
Это не сработало, братан - person Sardorek Aminjonov; 05.04.2021
comment
Опубликуйте код, в котором вы получаете данные, которые хотите обновить. - person Huthaifa Muayyad; 05.04.2021
comment
FoodRepository foodRepository; initState () {foodRepository = FoodRepository (категория: this.foodCategory); } - person Sardorek Aminjonov; 05.04.2021
comment
Просто преобразовал виджет в Stateful и написал код выше внутри - person Sardorek Aminjonov; 05.04.2021

Поскольку вы помещаете инициализацию _kTabPages и _kBottomNavBarItems в метод build(), этим переменным присваиваются новые значения каждый раз, когда происходит изменение состояния (когда вы меняете вкладки). Вот почему вкладки продолжают перерисовываться.

Чтобы остановить это, поместите свою инициализацию в initState(). Что-то вроде этого:

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,
      ),
    );
  }
}
person Bach    schedule 05.04.2021
comment
Спасибо за ответ. Но _currentTabIndex уже меняется и с этим проблем нет. Потому что я напечатал индекс на касании нижней панели. Проблема в том, что моя страница не обновляется, когда я повторно использую один виджет без сохранения состояния, в котором есть список элементов, поступающих из базы данных. Но он работает правильно, когда я использую разные виджеты. - person Sardorek Aminjonov; 05.04.2021
comment
@SardorekAminjonov Попробуйте добавить атрибут Key к каждому виджету FoodCategory, затем передать UniqueKey (как в обновленном ответе) и посмотрите, изменится ли он. - person Bach; 05.04.2021