gpt4 book ai didi

flutter - 如何在同一个 `ChangeNotifierProvider` 小部件上返回多个 `Expanded`

转载 作者:行者123 更新时间:2023-12-03 03:33:46 25 4
gpt4 key购买 nike

我正在尝试添加网格列表,同时添加第二个网格的项目时发现以下错误:

Error: Could not find the correct Provider<Cities> above this PropertiesGrid Widget

To fix, please:

* Ensure the Provider<Cities> is an ancestor to this PropertiesGrid Widget
* Provide types to Provider<Cities>
* Provide types to Consumer<Cities>
* Provide types to Provider.of<Cities>()
* Always use package imports. Ex: `import 'package:my_app/my_code.dart';
* Ensure the correct `context` is being used.

If none of these solutions work, please file a bug at:
https://github.com/rrousselGit/provider/issues
我认为我的 Home Screen 中的问题在下面的代码部分:
Expanded(
child: FutureBuilder<bool>(
future: getData(),
builder: (BuildContext context,
AsyncSnapshot<bool> snapshot) {
if (!snapshot.hasData) {
return const SizedBox();
} else {
return ChangeNotifierProvider(
create: (context) => Properties(),
child: PropertiesGrid(_showOnlyFavorites),
);
}
},
),
),
所以这是我在这类部分中划分的代码 Providers , Screens , Widgets如下图所示:
enter image description here
这是我的主屏幕:
import 'package:flutter/rendering.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../providers/properties.dart';
import '../providers/cities.dart';
import '../widgets/properties_grid.dart';
import '../app_theme.dart';

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

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

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
int currentTab = 0;
ScrollController _scrollController = ScrollController();
bool _showBottomBar = true;

_scrollListener() {
if (_scrollController.position.userScrollDirection ==
ScrollDirection.reverse) {
setState(() {
_showBottomBar = false;
});
} else if (_scrollController.position.userScrollDirection ==
ScrollDirection.forward) {
setState(() {
_showBottomBar = true;
});
}
}
var _showOnlyFavorites = false;
AnimationController animationController;
bool multiple = true;

@override
void initState() {
animationController = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
_scrollController.addListener(_scrollListener);
super.initState();
}

Future<bool> getData() async {
await Future<dynamic>.delayed(const Duration(milliseconds: 0));
return true;
}

@override
void dispose() {
animationController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 6, // Added
initialIndex: 0,
child: Scaffold(
resizeToAvoidBottomPadding: false,
extendBody: true,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: AnimatedContainer(
duration: Duration(milliseconds: 500),
child: _showBottomBar
? BottomAppBar(
elevation: 0,
shape: CircularNotchedRectangle(),
notchMargin: 10,
child: Container(
height: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
MaterialButton(
padding: EdgeInsets.all(0),
minWidth: 155,
onPressed: () {
setState(() {
// currentScreen =
// Chat(); // if user taps on this dashboard tab will be active
currentTab = 1;
});
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.home,
color: currentTab == 1
? Colors.blue
: Colors.grey,
),
Text(
'Home',
style: TextStyle(
color: currentTab == 1
? Colors.blue
: Colors.grey,
),
),
],
),
)
],
),

// Right Tab bar icons

Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
MaterialButton(
padding: EdgeInsets.all(0),
minWidth: 60,
onPressed: () {
setState(() {
// currentScreen =
// Settings(); // if user taps on this dashboard tab will be active
currentTab = 3;
});
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.view_list,
color: currentTab == 3
? Colors.blue
: Colors.grey,
),
Text(
'Property List',
style: TextStyle(
color: currentTab == 3
? Colors.blue
: Colors.grey,
),
),
],
),
),
MaterialButton(
padding: EdgeInsets.all(0),
minWidth: 77,
onPressed: () {
setState(() {
// currentScreen =
// Settings(); // if user taps on this dashboard tab will be active
currentTab = 4;
});
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.location_searching,
color: currentTab == 4
? Colors.blue
: Colors.grey,
),
Text(
'Map',
style: TextStyle(
color: currentTab == 4
? Colors.blue
: Colors.grey,
),
),
],
),
),
],
)
],
),
),
)
: Container(
color: Colors.white,
width: MediaQuery.of(context).size.width,
),
),
backgroundColor: AppTheme.white,
body: Stack(
children: <Widget>[
FutureBuilder<bool>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (!snapshot.hasData) {
return const SizedBox();
} else {
return Padding(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
appBar(),
tabBar(),
Expanded(
child: FutureBuilder<bool>(
future: getData(),
builder: (BuildContext context,
AsyncSnapshot<bool> snapshot) {
if (!snapshot.hasData) {
return const SizedBox();
} else {
return ChangeNotifierProvider(
create: (context) => Properties(),
child: PropertiesGrid(_showOnlyFavorites),
);
}
},
),
),
],
),
);
}
},
),
],
),
),
);
}

Widget appBar() {
return SizedBox(
height: AppBar().preferredSize.height,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 8, left: 8),
child: Container(
width: AppBar().preferredSize.height - 8,
height: AppBar().preferredSize.height - 8,
),
),
Expanded(
child: Center(
child: Padding(
padding: const EdgeInsets.only(top: 4),
child:
Image.asset('assets/images/logo.png', fit: BoxFit.contain),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8, right: 8),
child: Container(
width: AppBar().preferredSize.height - 8,
height: AppBar().preferredSize.height - 8,
color: Colors.white,
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius:
BorderRadius.circular(AppBar().preferredSize.height),
child: Icon(
Icons.location_on,
color: AppTheme.dark_grey,
),
onTap: () {
setState(() {
multiple = !multiple;
});
},
),
),
),
),
],
),
);
}

Widget tabBar() {
return SizedBox(
height: AppBar().preferredSize.height,
child: TabBar(
isScrollable: true,
unselectedLabelColor: Colors.green,
labelColor: Colors.blue,
indicatorColor: Colors.blue,
labelStyle: TextStyle(fontSize: 15.0,fontStyle: FontStyle.italic),
tabs: [
Tab(
child: Text('All'),
),
Tab(
child: Text('Office'),
),
Tab(
child: Text('Commercial'),
),
Tab(
child: Text('Land'),
),
Tab(
child: Text('House/Villa'),
),
Tab(
child: Text('Apartement'),
),
],
),
);
}
}

这是 Grid 小部件的列表:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import './province_item.dart';
import './property_item.dart';

import '../providers/cities.dart';
import '../providers/properties.dart';

// import '../providers/properties.dart';

class PropertiesGrid extends StatelessWidget {
final bool showFavs;

PropertiesGrid(this.showFavs);

@override
Widget build(BuildContext context) {
final propertiesData = Provider.of<Properties>(context);
final citiesData = Provider.of<Cities>(context);
// final productData = Provider.of<Cities>(context);
final properties = showFavs ? propertiesData.favoriteItems : propertiesData.items;
final cities = citiesData.items;
return Container(
color: Colors.transparent,
child: SingleChildScrollView(
child: Column(
children: [
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(6.0),
child: Align(
child: Text(
"Show All",
style: TextStyle(
fontSize: 16,
fontStyle: FontStyle.italic,
color: Colors.green),
),
alignment: Alignment.topLeft,
),
),
Container(
margin: const EdgeInsets.only(left: 95.0),
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Align(
child: Text(
"Popular Properties",
style: TextStyle(
fontSize: 18,
fontStyle: FontStyle.italic,
color: Colors.black.withOpacity(0.8)),
),
alignment: Alignment.topRight,
),
),
),
],
),
SizedBox(
height: 250,
child: Column(
children: <Widget>[
Expanded(
child: GridView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: properties.length,
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
// builder: (c) => products[i],
value: properties[i],
child: PropertyItem(
// products[i].id,
// products[i].title,
// products[i].imageUrl,
),
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: 3 / 4,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
scrollDirection: Axis.horizontal,
),
),
],
),
),
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(6.0),
child: Align(
child: Text(
"Show All",
style: TextStyle(
fontSize: 16,
fontStyle: FontStyle.italic,
color: Colors.green),
),
alignment: Alignment.topLeft,
),
),
Container(
margin: const EdgeInsets.only(left: 180.0),
child: Padding(
padding: const EdgeInsets.all(6.0),
child: Align(
child: Text(
"Province",
style: TextStyle(
fontSize: 18,
fontStyle: FontStyle.italic,
color: Colors.black.withOpacity(0.8)),
),
alignment: Alignment.topRight,
),
),
),
],
),
SizedBox(
height: 250,
child: Column(
children: <Widget>[
Expanded(
child: GridView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: cities.length,
itemBuilder: (ctx, i) => ChangeNotifierProvider.value(
// builder: (c) => products[i],
value: cities[i],
child: ProvinceItem(
// products[i].id,
// products[i].title,
// products[i].imageUrl,
),
),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1,
childAspectRatio: 3 / 4,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
scrollDirection: Axis.horizontal,
),
),
],
),
),
],
),
),
);
}
}

这是与小部件相关的省份项目:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../providers/city.dart';

class ProvinceItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final city = Provider.of<City>(context, listen: false);
return Padding(
padding: const EdgeInsets.all(8.0),
child: InkWell(
splashColor: Colors.transparent,
onTap: () => {},
child: Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.grey.withOpacity(0.6),
offset: const Offset(2.5, 2.5),
blurRadius: 16,
),
],
),
margin: EdgeInsets.all(2),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
bottomLeft: Radius.circular(15),
bottomRight: Radius.circular(15),
),
child: Image.asset(
city.cityImage,
fit: BoxFit.cover,
),
),
),
),
);
}
}

这是 City提供者:
import 'package:flutter/material.dart';

class City with ChangeNotifier {
final String cityId;
final String cityName;
final String cityImage;

City({
@required this.cityId,
@required this.cityName,
@required this.cityImage,
});
}

我把这个虚拟数据放在 Provider 中,就像下面的代码一样:
import '../providers/city.dart';
import 'package:flutter/material.dart';
// import './property.dart';

class Cities with ChangeNotifier {
List<City> _items = [
City(
cityId: 'city1',
cityName: 'Amman',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city2',
cityName: 'Jerash',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city3',
cityName: 'Karak',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city4',
cityName: 'Aqaba',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city5',
cityName: 'Zarqa',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city6',
cityName: 'Madaba',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city7',
cityName: 'Balqa',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city8',
cityName: 'Mafraq',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city9',
cityName: 'Maan',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city10',
cityName: 'Ajloun',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city11',
cityName: 'Irbid',
cityImage: 'assets/images/amman.png',
),
City(
cityId: 'city12',
cityName: 'Tafila',
cityImage: 'assets/images/amman.png',
),
];

List<City> get items {
return [..._items];
}
City findById(String cityId) {
return _items.firstWhere((cit) => cit.cityId == cityId);
}
}

我很抱歉添加了很多代码我试图添加所有需要的信息......
请是否有任何缺失的信息让我知道在问题中添加它..
已编辑
这是调试横幅屏幕:
DeBug Banner

最佳答案

哇,那是你发布的相当多的代码。我必须承认我没有仔细研究它,但我想我明白了问题所在:正如错误消息指出的那样,您没有注入(inject)类型为 Cities 的 Provider在上下文树中 PropertiesGrid 的点上方建成。
PropertiesGrid 中的这些行:

final propertiesData = Provider.of<Properties>(context);
final citiesData = Provider.of<Cities>(context);

您正在请求 Properties 的实例和 Cities 之一从上下文树中的点上方。如果您不满足此类要求,提供商将无情地对您进行崩溃。事实上,你得到了:
(22371): Error: Could not find the correct Provider<Cities> above this PropertiesGrid Widget

所以..让我们看看你的 PropertiesGrid小部件内置在您的主页中:
if (!snapshot.hasData) {
return const SizedBox();
} else {
return ChangeNotifierProvider(
create: (context) => Properties(),
child: PropertiesGrid(_showOnlyFavorites),
);
}

有一个提供程序可以正确注入(inject) Properties上面的实例 PropertiesGrid ,但没有人提供 Cities 的实例,因此您的小部件具有无法满足的依赖关系。

对于快速解决方案,我建议您使用 MultiProvider 注入(inject)两个依赖项。像这样
if (!snapshot.hasData) {
return const SizedBox();
} else {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => Properties()),
ChangeNotifierProvider(create: (context) => Cities()),
],
child: PropertiesGrid(_showOnlyFavorites),
);
}

注意使用 MultiProvider不是强制性的:即使在 HomePage 树的不同高度,您也可以使用两个提供程序注入(inject)这两个实例。只要这两个提供程序构建在 PropertiesGrid 之上你很厉害。

如果 Provider 最初看起来有点难以完全掌握,请不要担心。一旦你掌握了它,它就会成为一个非常强大的状态管理工具。我建议你看一些 online article或教程以获得一些练习。

关于flutter - 如何在同一个 `ChangeNotifierProvider` 小部件上返回多个 `Expanded`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62232360/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com