【问题标题】:Using TextField inside a Streambuilder在 Streambuilder 中使用 TextField
【发布时间】:2019-01-05 08:27:19
【问题描述】:

我们如何在 StreamBuilder 中添加 TextField? 我有一个 TextField / TextFormField 作为 StreamBuilder 或 FutureBuilder 的构建器函数内的小部件之一,每当我们尝试与文本字段交互时,它只会刷新整个构建器小部件并再次调用流/未来。

body: StreamBuilder(
      stream: getClientProfile().snapshots(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.active) {
          print(snapshot.data.data);
          Client tempClient = Client.from(snapshot.data);
          print('details = ${tempClient.representative.email} ${tempClient
              .address.location} ${tempClient.businessDescription}');
          return Container(
            child: Column(
              children: <Widget>[
                TextFormField(

                )
              ],
            ),
          );
        } else if (snapshot.connectionState == ConnectionState.waiting) {
          return Center(child: CircularProgressIndicator());
        } else {
          return Center(
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Icon(Icons.error),
                ),
                Text('Error loading data')
              ],
            ),
          );
        }
      }),

和firestore功能

DocumentReference getClientProfile() {
   return _firestore.collection(SELLERS_COLLECTION).document(_uid);
}

我想要实现的是从 firestore 文档中预先填写数据的表单,基本上是一个编辑表单。有没有其他方法可以达到同样的效果,或者我在结构上做错了什么?

编辑:

建议修改后的代码。

    import 'package:flutter/material.dart';
import 'Utils/globalStore.dart';
import 'models/client_model.dart';
import 'dart:async';

class EditProfileInformation extends StatefulWidget {
  @override
  EditProfileInformationState createState() {
    return new EditProfileInformationState();
  }
}

class EditProfileInformationState extends State<EditProfileInformation> {
  Stream dbCall;
  final myController = TextEditingController();

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    dbCall = getClientProfile().snapshots();
    myController.addListener(_printLatestValue);
  }

  _printLatestValue() {
    print("Second text field: ${myController.text}");
  }

  @override
  void dispose() {
    myController.removeListener(_printLatestValue);
    myController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
//      key: _scaffoldKey,
      appBar: AppBar(
        title: Text(
          'Edit profile',
          style: TextStyle(),
        ),
      ),

      body: StreamBuilder(
          stream: dbCall,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.active) {
              print(snapshot.data.data);
              Client tempClient = Client.from(snapshot.data);
              print('details = ${tempClient.representative.email} ${tempClient
                  .address.location} ${tempClient.businessDescription}');
              return Container(
                child: Column(
                  children: <Widget>[
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: TextField(
                        controller: myController,
                      ),
                    )
                  ],
                ),
              );
            } else if (snapshot.connectionState == ConnectionState.waiting) {
              return Center(child: CircularProgressIndicator());
            } else {
              return Center(
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Icon(Icons.error),
                    ),
                    Text('Error loading data')
                  ],
                ),
              );
            }
          }),
      floatingActionButton: FloatingActionButton(
        onPressed: () {

        },
        child: Icon(Icons.done),
      ),
    );
  }
}

【问题讨论】:

  • 这是在无状态小部件而不是有状态小部件中吗?
  • @JonahWilliams 是的,它在一个无状态的小部件中,我也尝试了有状态的......结果相同。

标签: firebase dart google-cloud-firestore flutter


【解决方案1】:

为了正确使用 StreamBuilder,您必须确保您正在使用的流缓存在 State 对象上。虽然 StreamBuilder 可以正确处理从流中获取新事件,但接收全新的 Stream 将强制它完全重建。在您的情况下,getClientProfile().snapshots() 将在调用时创建一个全新的 Stream,从而破坏您的文本字段的所有状态。

class Example extends StatefulWidget {
  @override
  State createState() => new ExampleState();
}

class ExampleState extends State<Example> {
  Stream<SomeType> _stream;

  @override
  void initState() {
    // Only create the stream once
    _stream = _firestore.collection(collection).document(id);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new StreamBuilder(
      stream: _stream,
      builder: (context, snapshot) {
        ...

      },
    );
  }
}

编辑:听起来我无法从您提供的代码 sn-p 诊断出其他问题。

【讨论】:

  • 是的,这是有道理的。当我这样放置时,小部件不再刷新。
  • 但是,再次调用流的问题依然存在。与文本字段的交互仍会触发未来或流调用。构建器内的任何其他小部件都不会发生(例如:DropDownButton)。 Firestore 文档读取是收费的:P 因此问题。
  • 你在使用 TextEditingController 吗?
  • 是的,有/没有 TextEditingController 仍然会进行调用。
  • 你能把剩下的代码贴出来看看你是如何使用控制器的吗?
猜你喜欢
  • 2020-04-21
  • 2019-05-10
  • 2019-09-02
  • 2019-08-13
  • 2021-08-27
  • 2020-12-19
  • 1970-01-01
  • 2022-12-25
  • 2019-09-01
相关资源
最近更新 更多