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 传递给另一个类的主要内容,如果未能解决你的问题,请参考以下文章

如何将值从javascript变量传递给剃刀变量?

如何将值从angularjs传递给节点[重复]

Java:如何将值从类/bean传递给servlet

如何将值从组件传递给道具并设置状态

Laravel:如何将值从控制器发送到模型?

如何将值从 tableview 传递到 collectionview