0

我正在尝试与提供者一起学习正确的状态管理,但我遇到了一个问题,我在这里遇到了麻烦。据我所知,我正在按照三个单独的提供者教程中的说明做所有事情。我也成功地将它用于我的数据表,没有任何问题。但是,当我尝试在小部件树上为我的 BottomNavigationBar 和我的 appBar 使用提供程序时,我不断收到错误消息和失败。

我想让我的底部导航栏与我的“零屏幕”状态分开。因此,我根据索引设置了一个带有底部导航栏按钮按下的 int,这应该更新我的 GlobalData pageSelection 索引。然后我为三元运算符在树上访问它。但我收到一个奇怪的错误,说它不在小部件树中......

我尝试做错误建议所述的事情,但没有运气。

任何帮助表示赞赏!

import 'package:flutter/material.dart';

class GlobalData extends ChangeNotifier {
  int pageSelectionIndex = 0;

  void updatePageSelection(int index) {
    pageSelectionIndex = index;
    notifyListeners();
  }
}

底部导航栏

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fp_provider_demo_one/models/global_data.dart';
import 'package:fp_provider_demo_one/screens/balance_screen.dart';
import 'package:fp_provider_demo_one/screens/subtract_screen.dart';
import 'package:fp_provider_demo_one/screens/add_screen.dart';
import 'package:fp_provider_demo_one/screens/inquiry_screen.dart';
import 'package:provider/provider.dart';

// ignore: must_be_immutable
class BottomNavBar extends StatefulWidget {
  @override
  _BottomNavBarState createState() => _BottomNavBarState();
}

class _BottomNavBarState extends State<BottomNavBar> {
  int _currentTabIndex = 0;

  @override
  Widget build(BuildContext context) {
    final _tabPages = <Widget>[
      AddScreen(),
      SubtractScreen(),
      BalanceScreen(),
      InquiryScreen()
    ];

    final _navBarItems = <BottomNavigationBarItem>[
      const BottomNavigationBarItem(
          icon: Icon(Icons.add_circle), label: 'Add'),
      const BottomNavigationBarItem(
          icon: Icon(Icons.remove_circle), label: 'Subtract'),
      const BottomNavigationBarItem(
          icon: Icon(Icons.grid_on_rounded), label: 'Balance'),
      const BottomNavigationBarItem(
          icon: Icon(Icons.show_chart), label: 'Inquiry'),
    ];

    assert(_tabPages.length == _navBarItems.length);
    final navBar = BottomNavigationBar(
      items: _navBarItems,
      showUnselectedLabels: true,
      showSelectedLabels: true,
      unselectedItemColor: Colors.grey,
      selectedItemColor: Colors.orange,
      currentIndex: _currentTabIndex,
      type: BottomNavigationBarType.fixed,
      onTap: (int index) {
        Provider.of<GlobalData>(context).updatePageSelection(index);
        setState(() {
          _currentTabIndex = index;
        });
      },
    );
    return Scaffold(
      body: _tabPages[_currentTabIndex],
      bottomNavigationBar: navBar,
    );
  }
}

零屏幕:

///
///
/// Holds bottom nav bar which in turn switches through screens

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:fp_provider_demo_one/models/global_data.dart';
import 'package:fp_provider_demo_one/widgets/bottom_nav_bar.dart';
import 'package:provider/provider.dart';

class ZeroScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    int _selectedIndex = Provider.of<GlobalData>(context).pageSelectionIndex;
    return Scaffold(
      appBar: AppBar(
        title: (_selectedIndex == 0)
            ? Text('Add')
            : (_selectedIndex == 1)
                ? Text('Subtract')
                : (_selectedIndex == 2)
                    ? Text('Balance')
                    : Text('Inquiry'),
        backgroundColor: (_selectedIndex == 0)
            ? Colors.green
            : (_selectedIndex == 1)
                ? Colors.red
                : (_selectedIndex == 2)
                    ? Colors.blue
                    : Colors.orange,
      ),
      bottomNavigationBar: BottomNavBar(),
    );
  }
}

错误:

======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Tried to listen to a value exposed with provider, from outside of the widget tree.

This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.

To fix, write:
Provider.of<GlobalData>(context, listen: false);

It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.

The context used was: BottomNavBar(state: _BottomNavBarState#38ad7)
'package:provider/src/provider.dart':
Failed assertion: line 262 pos 7: 'context.owner.debugBuilding ||
          listen == false ||
          debugIsInInheritedProviderUpdate'

When the exception was thrown, this was the stack: 
#2      Provider.of (package:provider/src/provider.dart:262:7)
#3      _BottomNavBarState.build.<anonymous closure> (package:fp_provider_demo_one/widgets/bottom_nav_bar.dart:49:18)
#4      _BottomNavigationBarState._createTiles.<anonymous closure> (package:flutter/src/material/bottom_navigation_bar.dart:974:26)
#5      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:991:20)
#6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#035fc
  debugOwner: GestureDetector
  state: ready
  won arena
  finalPosition: Offset(144.0, 783.0)
  finalLocalPosition: Offset(46.5, 21.5)
  button: 1
  sent tap down
====================================================================================================

4

2 回答 2

2

您可以在第 1 步下面复制粘贴运行完整代码
:使用Provider.of<GlobalData>(context, listen: false).updatePageSelection

onTap: (int index) {
        Provider.of<GlobalData>(context, listen: false)
            .updatePageSelection(index);

第2步:ChangeNotifierProvider放入main()

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => GlobalData(),
      child: MyApp(),
    ),
  );
}

工作演示

在此处输入图像描述

完整代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class GlobalData extends ChangeNotifier {
  int pageSelectionIndex = 0;

  void updatePageSelection(int index) {
    pageSelectionIndex = index;
    notifyListeners();
  }
}

class BottomNavBar extends StatefulWidget {
  @override
  _BottomNavBarState createState() => _BottomNavBarState();
}

class _BottomNavBarState extends State<BottomNavBar> {
  int _currentTabIndex = 0;

  @override
  Widget build(BuildContext context) {
    final _tabPages = <Widget>[
      AddScreen(),
      SubtractScreen(),
      BalanceScreen(),
      InquiryScreen()
    ];

    final _navBarItems = <BottomNavigationBarItem>[
      const BottomNavigationBarItem(icon: Icon(Icons.add_circle), label: 'Add'),
      const BottomNavigationBarItem(
          icon: Icon(Icons.remove_circle), label: 'Subtract'),
      const BottomNavigationBarItem(
          icon: Icon(Icons.grid_on_rounded), label: 'Balance'),
      const BottomNavigationBarItem(
          icon: Icon(Icons.show_chart), label: 'Inquiry'),
    ];

    assert(_tabPages.length == _navBarItems.length);
    final navBar = BottomNavigationBar(
      items: _navBarItems,
      showUnselectedLabels: true,
      showSelectedLabels: true,
      unselectedItemColor: Colors.grey,
      selectedItemColor: Colors.orange,
      currentIndex: _currentTabIndex,
      type: BottomNavigationBarType.fixed,
      onTap: (int index) {
        Provider.of<GlobalData>(context, listen: false)
            .updatePageSelection(index);
        setState(() {
          _currentTabIndex = index;
        });
      },
    );
    return Scaffold(
      body: _tabPages[_currentTabIndex],
      bottomNavigationBar: navBar,
    );
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => GlobalData(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ZeroScreen(),
    );
  }
}

class ZeroScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    int _selectedIndex = Provider.of<GlobalData>(context).pageSelectionIndex;
    return Scaffold(
      appBar: AppBar(
        title: (_selectedIndex == 0)
            ? Text('Add')
            : (_selectedIndex == 1)
                ? Text('Subtract')
                : (_selectedIndex == 2)
                    ? Text('Balance')
                    : Text('Inquiry'),
        backgroundColor: (_selectedIndex == 0)
            ? Colors.green
            : (_selectedIndex == 1)
                ? Colors.red
                : (_selectedIndex == 2)
                    ? Colors.blue
                    : Colors.orange,
      ),
      bottomNavigationBar: BottomNavBar(),
    );
  }
}

class AddScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("AddScreen"));
  }
}

class SubtractScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("SubtractScreen"));
  }
}

class BalanceScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("BalanceScreen"));
  }
}

class InquiryScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(child: Text("InquiryScreen"));
  }
}
于 2021-03-16T06:28:19.757 回答
1

您是否尝试过在 onTap 之外声明您的提供程序变量?例如:

final provider = Provider.of<GlobalData>(context);
onTap:(index){
provider.updatePageSelection(index);
}

另一种可能性是context无法正确到达onTap,正如它在日志中所说,您应该listen: false在声明提供者时设置,例如:

Provider.of<GlobalData>(context, listen: false);
于 2021-03-16T06:13:02.757 回答