Flutter Firestore UI构建插件firestore_ui的使用
Flutter Firestore UI构建插件firestore_ui的使用
firestore_ui
这个项目最初作为一个PR提交到官方的cloud_firestore插件,但由于他们仍在完善主要功能,因此不得不推迟。该项目基于firebase_database版本。
但是不用担心,我的各位Cloud Firestore用户们,这是一个从那个PR中提取出的主要代码包,现在可以供你们使用!
自定义参数
bool linear
- 这将使它仅使用.add
而不是.insert
,这通常在列表更新时(如聊天)导致更少的顺序问题。void onLoaded(QuerySnapshot snapshot)
- 您可以使用此方法访问来自流的最新QuerySnapshot
。bool filter(DocumentSnapshot snapshot)
- 这允许你在渲染阶段过滤特定的快照,如果返回true
则该项将被过滤。bool debug
- 设置此选项可以看到与插入/删除/更新项目相关的所有日志。
如何使用
以下所有示例均来自实际的example
文件夹,请运行它们以查看其行为!
列表
将其设置为像ListView.builder
一样:
FirestoreAnimatedList(
query: query,
itemBuilder: (
BuildContext context,
DocumentSnapshot snapshot,
Animation<double> animation,
int index,
) => FadeTransition(
opacity: animation,
child: MessageListTile(
index: index,
document: snapshot,
onTap: _removeMessage,
),
),
);
网格
将其设置为像GridView.count
一样,并同时设置必要的crossAxisCount
,SliverGridDelegateWithFixedCrossAxisCount
的所有其他参数也可用:
FirestoreAnimatedGrid(
query: query,
crossAxisCount: 2,
mainAxisSpacing: 4.0,
childAspectRatio: 1.0,
crossAxisSpacing: 4.0,
itemBuilder: (
BuildContext context,
DocumentSnapshot snapshot,
Animation<double> animation,
int index,
) => FadeTransition(
opacity: animation,
child: MessageGridTile(
index: index,
document: snapshot,
onTap: _removeMessage,
),
),
);
交错网格
将其设置为像StaggeredGridView.countBuilder
一样,并同时设置必要的crossAxisCount
和staggeredTileBuilder
:
FirestoreAnimatedStaggered(
query: query,
staggeredTileBuilder: (int index, DocumentSnapshot snapshot) => StaggeredTile.count(2, index.isEven ? 2 : 1),
crossAxisCount: 4,
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
itemBuilder: (
BuildContext context,
DocumentSnapshot snapshot,
Animation<double> animation,
int index,
) => FadeTransition(
opacity: animation,
child: MessageGridTile(
index: index,
document: snapshot,
onTap: _removeMessage,
),
),
);
特别感谢@letsar的flutter_staggered_grid_view
包!没有它,这部分功能就不会可用;请查看库以了解更多信息!
完整示例
import 'package:firebase_core/firebase_core.dart' show Firebase;
import 'package:firestore_ui/firestore_ui.dart';
import 'package:firestore_ui_example/firebase_options.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final String title = 'firestore_ui example';
typedef OnSnapshot = Function(DocumentSnapshot<Map<String, dynamic>>?);
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
runApp(
MaterialApp(
title: title,
home: MyHomePage(firestore: FirebaseFirestore.instance),
),
);
}
class Movie {
Movie({
required this.genre,
required this.likes,
required this.poster,
required this.rated,
required this.runtime,
required this.title,
required this.year,
});
Movie.fromJson(Map<String, Object?> json)
: this(
genre: (json['genre']! as List).cast<String>(),
likes: json['likes']! as int,
poster: json['poster']! as String,
rated: json['rated']! as String,
runtime: json['runtime']! as String,
title: json['title']! as String,
year: json['year']! as int,
);
final String poster;
final int likes;
final String title;
final int year;
final String runtime;
final String rated;
final List<String> genre;
Map<String, Object?> toJson() {
return {
'genre': genre,
'likes': likes,
'poster': poster,
'rated': rated,
'runtime': runtime,
'title': title,
'year': year,
};
}
}
class MovieListTile extends StatelessWidget {
final int index;
final DocumentSnapshot<Movie>? document;
const MovieListTile({
Key? key,
required this.index,
required this.document,
}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
String title = 'No movie retrieved!';
if (document != null && document!.exists) {
final receivedMessage = document!.data()?.title;
if (receivedMessage != null) title = receivedMessage;
}
return ListTile(
title: Text(title),
subtitle: Text('Item ${this.index + 1}'),
);
}
}
class MessageGridTile extends StatelessWidget {
final int index;
final DocumentSnapshot<Movie>? document;
const MessageGridTile({
Key? key,
required this.index,
required this.document,
}) : super(key: key);
[@override](/user/override)
Widget build(BuildContext context) {
return Container(
color: Colors.green,
child: Center(
child: CircleAvatar(
backgroundColor: Colors.white,
child: Text('${this.index + 1}'),
),
),
);
}
}
class MyHomePage extends StatefulWidget {
final FirebaseFirestore firestore;
MyHomePage({Key? key, required this.firestore}) : super(key: key);
[@override](/user/override)
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final PageController _controller = PageController(initialPage: 0, keepPage: true);
int _currentIndex = 0;
void _updateIndex(int value) {
if (mounted) {
setState(() => _currentIndex = value);
_controller.jumpToPage(_currentIndex);
}
}
Query<Movie> get query => widget.firestore.collection('firestore-example-app').withConverter<Movie>(
fromFirestore: (snapshots, _) => Movie.fromJson(snapshots.data()!),
toFirestore: (movie, _) => movie.toJson(),
).limit(20);
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: _updateIndex,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.filter_1),
label: "List",
),
BottomNavigationBarItem(
icon: Icon(Icons.filter_2),
label: "Grid",
),
BottomNavigationBarItem(
icon: Icon(Icons.filter_3),
label: "Staggered",
),
],
),
appBar: AppBar(
title: Text(title),
),
body: PageView(
controller: _controller,
children: [
FirestoreAnimatedList<Movie>(
debug: false,
key: ValueKey("list"),
query: query,
onLoaded: (snapshot) => print("Received on list: ${snapshot.docs.length}"),
itemBuilder: (
BuildContext context,
snapshot,
Animation<double> animation,
int index,
) =>
FadeTransition(
opacity: animation,
child: MovieListTile(
index: index,
document: snapshot,
),
),
),
FirestoreAnimatedGrid<Movie>(
key: ValueKey("grid"),
query: query,
onLoaded: (snapshot) => print("Received on grid: ${snapshot.docs.length}"),
crossAxisCount: 2,
itemBuilder: (
BuildContext context,
snapshot,
Animation<double> animation,
int index,
) {
return FadeTransition(
opacity: animation,
child: MessageGridTile(
index: index,
document: snapshot,
),
);
},
),
FirestoreAnimatedStaggered<Movie>(
key: ValueKey("staggered"),
onLoaded: (snapshot) => print("Received on staggered: ${snapshot.docs.length}"),
staggeredTileBuilder: (int index, DocumentSnapshot? snapshot) => StaggeredTile.count(2, index.isEven ? 2 : 1),
crossAxisCount: 4,
query: query,
itemBuilder: (
BuildContext context,
snapshot,
Animation<double> animation,
int index,
) {
return FadeTransition(
opacity: animation,
child: MessageGridTile(
index: index,
document: snapshot,
),
);
},
),
],
),
);
}
}
更多关于Flutter Firestore UI构建插件firestore_ui的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter Firestore UI构建插件firestore_ui的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,firestore_ui
是一个 Flutter 插件,它简化了从 Firestore 数据库读取数据并显示在 UI 上的过程。这个插件利用了 Flutter 的 StreamBuilder
和 Firestore 的实时数据特性,能够让你快速构建响应式 UI。
以下是一个简单的示例,展示了如何使用 firestore_ui
插件来从一个 Firestore 集合中读取数据并显示在 ListView
中。
首先,确保你已经在 pubspec.yaml
文件中添加了 firestore_ui
依赖:
dependencies:
flutter:
sdk: flutter
cloud_firestore: ^x.y.z # 请替换为最新版本号
firestore_ui: ^x.y.z # 请替换为最新版本号
然后运行 flutter pub get
来安装依赖。
接下来,创建一个 Flutter 应用并配置 Firestore。以下是一个完整的示例代码:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firestore_ui/firestore_ui.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Firestore UI Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
final CollectionReference<Map<String, dynamic>> usersCollection =
FirebaseFirestore.instance.collection('users');
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Firestore UI Demo'),
),
body: FirestoreQueryBuilder<Map<String, dynamic>>(
query: usersCollection.orderBy('name'), // 假设每个用户文档都有一个 'name' 字段
builder: (context, snapshot, error) {
if (error != null) {
return Text('Error: ${error.message}');
}
if (snapshot == null || snapshot.docs.isEmpty) {
return Center(child: Text('No data'));
}
return ListView.builder(
itemCount: snapshot.docs.length,
itemBuilder: (context, index) {
final doc = snapshot.docs[index];
return ListTile(
title: Text(doc.data()['name']),
subtitle: Text(doc.data()['email']), // 假设每个用户文档都有一个 'email' 字段
);
},
);
},
),
);
}
}
在这个示例中:
- 依赖配置:我们在
pubspec.yaml
中添加了cloud_firestore
和firestore_ui
依赖。 - Firestore 集合引用:在
MyHomePage
类中,我们创建了一个对 Firestore 集合users
的引用。 - FirestoreQueryBuilder:我们使用
FirestoreQueryBuilder
小部件来查询 Firestore 数据。这个查询会按照用户的name
字段进行排序。 - UI 构建:根据查询结果,我们构建了一个
ListView
来显示每个用户的name
和email
。
确保你已经配置了 Firebase 项目,并在你的 Flutter 应用中正确初始化了 Firestore。这通常涉及到在 main.dart
或其他合适的位置添加 Firebase 初始化代码。
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
这个示例展示了 firestore_ui
插件的基本用法,帮助你快速构建响应式 Firestore 数据驱动的 UI。根据你的具体需求,你可以进一步自定义和扩展这个示例。