【问题标题】:How to sync Flutter TextField with Firestore field?如何将 Flutter TextField 与 Firestore 字段同步?
【发布时间】:2018-09-22 11:36:28
【问题描述】:
我在 Firestore 中有 task 文档,其中有 todo 字段,在 Flutter UI 中有 TextField。
请告知如何使textfield 与todo 字段同步,即
- 任何时候,
textfield 中的文本会随着用户的输入而更改,请使用刚刚输入的值更新 todo 字段。
-
todo 字段随时更新(在 Firestore 控制台中或由其他用户手动更新),将 textfield 更新为最新值。
谢谢!
【问题讨论】:
标签:
firebase
flutter
google-cloud-firestore
【解决方案1】:
首先,将TextEditingController 提供给TextField(查看this 以获得完整示例)。
对于问题的第一部分,您需要向TextEditingController 提供listener。这个listener 应该触发这样的函数:
Future<void> _updateTaskValue(String text) {
Firestore().runTransaction((Transaction transaction) {
Firestore.instance.document([PATH OF YOUR DOCUMENT]).updateData({"todo": text});
});
}
假设text 是控制器的text 值。注意runTransaction是用来避免数据并发的。
对于问题的第二部分,您必须听文档。为此,请在 initState 和 StreamSubscription 中声明:
subscription = Firestore.instance.document("").snapshots().listen(
(DocumentSnapshot snapshot) => this._onDatabaseUpdate(snapshot));
每次更新内容时,此订阅都会触发一个函数(无论是当前用户更新TextField,其他用户更新它,还是从后台手动更新)。
下面调用的函数只是用新内容更新控制器的text 属性:
void _onDatabaseUpdate(DocumentSnapshot snapshot) {
setState(() {
_controller.text = snapshot.data["todo"];
});
}
有关完整示例,请参阅this gist。
【解决方案2】:
- TextField onChanged 更新 firebase 中的值。
- 监听 firebase 中的值变化并使用 TextEditingController 更新 TextField 的值。
代码如下:
import 'dart:async';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'TODO Screen',
theme: ThemeData(
primarySwatch: Colors.orange,
),
home: TODOScreen(),
);
}
}
class TODOScreen extends StatefulWidget {
@override
_TODOScreenState createState() => _TODOScreenState();
}
class _TODOScreenState extends State<TODOScreen> {
final _ref = FirebaseDatabase.instance.reference().child('todo_id').child('value');
TextEditingController _todoController = new TextEditingController();
StreamSubscription _subscription;
@override
void initState() {
super.initState();
_subscription = _ref.onValue.listen((data) {
String value = data.snapshot.value as String ?? "";
updateOnChanged(value);
});
}
saveOnChanged(String value) async {
await _ref.set(value);
}
updateOnChanged(String value) async {
setState(() {
_todoController.value = _todoController.value.copyWith(
text: value,
);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('TODO Screen'),
),
body: Center(
child: Container(
padding: EdgeInsets.all(10.0),
child: TextField(
decoration: InputDecoration(labelText: "TODO"),
maxLines: 5,
onChanged: saveOnChanged,
controller: _todoController,
),
),
),
);
}
@override
void dispose() {
_todoController.dispose();
if (_subscription != null) _subscription.cancel();
super.dispose();
}
}
希望有帮助!