Flutter:如何将值从 streamprovider / listview builder 传递给另一个类
Posted
技术标签:
【中文标题】Flutter:如何将值从 streamprovider / listview builder 传递给另一个类【英文标题】:Flutter: How to pass a value in to another class from a streamprovider / listview builder 【发布时间】:2020-12-30 04:00:10 【问题描述】:背景:
我正在尝试生成可滚动的图像列表视图。该屏幕将分为三个阶段:
最初列出某种类型的图像(在元数据中的 firestore 字段中定义) 当用户选择其中一个小部件时,图像将更改为不同类型的图像 最后,可选的第三阶段显示不同的类型每次按下时,所选图像将构建到一个新数组中,最终形成另一种由三个所选图像组成的图像视图,将在底部显示,单击按钮将读取“ 3 个选定图像的句子”。
我目前拥有的:
我通过调用包含 ListView 的类的 StreamProvider 提供了带有正确过滤图像的初始 ListView。目前这已被过滤,因为我对查询进行了硬编码。
这是最终显示 ListView 的屏幕
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:showmeapp/Screens/Home/image_list.dart';
import 'package:showmeapp/Services/database.dart';
import 'package:showmeapp/models/new_image.dart';
class Sentence extends StatelessWidget
@override
Widget build(BuildContext context)
return StreamProvider<List<NewImage>>.value(
value: FirestoreDatabaseService().firestoreImages,
child: Scaffold(
backgroundColor: Colors.blue[300],
appBar: AppBar(
title: Text('Make A Sentence'),
backgroundColor: Colors.blue[700],
elevation: 0.0,
),
body: ImageList(),
)
);
这是从该屏幕调用的 ImageList 类
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:showmeapp/Screens/Home/image_card.dart';
import 'package:showmeapp/models/new_image.dart';
class ImageList extends StatefulWidget
@override
_ImageListState createState() => _ImageListState();
class _ImageListState extends State<ImageList>
@override
Widget build(BuildContext context)
final images = Provider.of<List<NewImage>>(context) ?? [];
final requestImages = images.where((element) => element.imageClass == 'request').toList();
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: requestImages.length,
itemBuilder: (context, index)
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 24.0),
height: MediaQuery.of(context).size.height * 0.35,
child: ImageCard(newImage: requestImages[index]),
);
,
);
这是从 ImageList 类调用的自定义 ImageCard 类
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:showmeapp/Screens/Home/image_list.dart';
import 'package:showmeapp/models/new_image.dart';
class ImageCard extends StatelessWidget
final NewImage newImage;
ImageCard(this.newImage);
@override
Widget build(BuildContext context)
return Column(
children: [
Container(
width: MediaQuery.of(context).size.width * 0.3,
height: MediaQuery.of(context).size.height * 0.2,
child: Card(
elevation: 30.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
side: BorderSide(width: 2.0, color: Colors.blueAccent),
),
child: GestureDetector(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
'assets/$newImage.imageLocation',
scale: 0.8,
height: MediaQuery.of(context).size.height * 0.2,
width: MediaQuery.of(context).size.width * 0.1,
),
),
onTap: ()
// String optionSelected = newImage.imageClass;
,
),
),
),
Container(
width: MediaQuery.of(context).size.width * 0.3,
child: Padding(
padding: EdgeInsets.all(5.0),
child: Center(
child: Text(
newImage.imageDescription,
style: TextStyle(
fontSize: 40.0,
),
),
),
),
)
],
);
最后,为了完整起见,这是与 Firebase 相关的函数和所有这些背后的调用
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:showmeapp/models/new_image.dart';
// A class for the Firestore Database Service
class FirestoreDatabaseService
final String iid;
// Constructor for Database Class
FirestoreDatabaseService( this.iid );
// create a reference to the Firestore 'images' collection
final CollectionReference firestoreImageCollection = FirebaseFirestore.instance.collection('images');
// Add or update image data - This will be useful for initial creation of image meta data for the app
Future updateFirestoreImageData(String description, String location, String type, String category) async
return await firestoreImageCollection.doc(iid).set(
'image_category': category,
'image_description': description,
'image_location': location,
'image_type': type
);
// new image list from snapshot
List<NewImage> _newImageFromSnapshot(QuerySnapshot snapshot)
return snapshot.docs.map((doc)
return NewImage(
imageClass: doc.data()['image_class'] ?? '',
imageType: doc.data()['image_type'] ?? '',
imageCategory: doc.data()['image_category'] ?? '',
imageLocation: doc.data()['image_location'] ?? '',
imageDescription: doc.data()['image_description'] ?? ''
);
).toList();
// Get images from collection via stream
Stream<List<NewImage>> get firestoreImages
return firestoreImageCollection.snapshots()
.map(_newImageFromSnapshot);
我正在努力解决的问题:
当用户选择“请求”图像之一时,我想传递一个值,以便下一组显示的图像属于“对象”类型。
但是如果我通过它,它总是将请求的提供者作为 Null 发送并且什么都不返回。
不起作用的代码:
ImageList 类
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:showmeapp/Screens/Home/image_card.dart';
import 'package:showmeapp/models/new_image.dart';
class ImageList extends StatefulWidget
@override
_ImageListState createState() => _ImageListState();
String searchClass;
ImageList( this.searchClass );
class _ImageListState extends State<ImageList>
@override
Widget build(BuildContext context)
final String searchClass = ImageList().searchClass;
final images = Provider.of<List<NewImage>>(context) ?? [];
final requestImages = images.where((element) => element.imageClass == searchClass.toString()).toList();
print('search class is: $searchClass');
print('Class search class is: $ImageList().searchClass');
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: requestImages.length,
itemBuilder: (context, index)
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 24.0),
height: MediaQuery.of(context).size.height * 0.35,
child: ImageCard(newImage: requestImages[index]),
);
,
);
句子屏幕/小部件
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:showmeapp/Screens/Home/image_list.dart';
import 'package:showmeapp/Services/database.dart';
import 'package:showmeapp/models/new_image.dart';
class Sentence extends StatelessWidget
@override
Widget build(BuildContext context)
return StreamProvider<List<NewImage>>.value(
value: FirestoreDatabaseService().firestoreImages,
child: Scaffold(
backgroundColor: Colors.blue[300],
appBar: AppBar(
title: Text('Make A Sentence'),
backgroundColor: Colors.blue[700],
elevation: 0.0,
),
body: ImageList(searchClass: 'request',),
)
);
因此,传递“请求”字符串并将其包含在 where 子句中会导致 Null。它仅在我在 where 子句中硬指定“请求”时才有效。上面的示例不是来自所选图像的操作,但与我试图告诉它最初通过传递的值加载“请求”图像的原理相同。一旦我可以通过初始值,那么我希望任何进一步的传递将插入到位:-)
我尝试了类、类和状态中的变量的变体(就像现在一样),但似乎无法让它携带值。
我将如何实现这一目标?是否可以使用 StreamProvider / ListView 构建器?
更新 我的 NewImage 类如下:
class NewImage
final String imageType; // Whether the image is a Category image or Object Image
final String imageDescription; // Text to display with the image
final String imageLocation; // The URL or Location of the image
final String imageCategory; // The category that the image belongs to
final String imageClass; // A tag to identify the stage for sentences, such as Request, Object, Ending
NewImage( this.imageType, this.imageDescription, this.imageLocation, this.imageCategory, this.imageClass );
谢谢
安德鲁
【问题讨论】:
【参考方案1】:我不完全确定我是否理解你的问题,但是我认为你的问题是由这行引起的:
final images = Provider.of<List<NewImage>>(context) ?? [];
我假设你的 new_image.dart 模型是这样的:
class NewImage extends ChangeNotifier
List<Image> _imageList = [];
List<Image> get imageList => _imageList;
void fetchImages()
_imageList = fetchFunction();
notifyListeners();
....
如果是这种情况,您的代码应该是这样的:
final images = Provider.of<NewImage>(context, listen: false).imageList;
【讨论】:
嗨,我已经更新了我的帖子以显示 NewImage 类。但是不,它只是我的图像对象的标准模型以上是关于Flutter:如何将值从 streamprovider / listview builder 传递给另一个类的主要内容,如果未能解决你的问题,请参考以下文章