fluent_refresher 1.0.1
fluent_refresher: ^1.0.1 copied to clipboard
A powerful and easy-to-use pull-to-refresh and pull-up-to-load package for Flutter, providing a fluent user experience.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:fluent_refresher/fluent_refresher.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fluent Refresher Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyPage(),
);
}
}
class MyPage extends StatefulWidget {
const MyPage({super.key});
@override
State<MyPage> createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
// 创建控制器
final _controller = RefreshController();
List<Map<String, dynamic>> _items = [];
@override
void initState() {
super.initState();
// 初始加载数据
_items = _generateItems(200);
}
// 辅助函数:生成带图片和文本的数据
List<Map<String, dynamic>> _generateItems(int count, {int offset = 0}) {
return List.generate(count, (i) {
final index = i + offset;
return {
'id': index,
'title': '项目标题 ${index + 1}',
'subtitle': '这是一个关于项目${index + 1}的详细描述内容。',
// 使用 picsum.photos 获取随机图片,用 id 作为 seed 保证图片稳定
'imageUrl': 'https://picsum.photos/seed/${index + 1}/200/200',
};
});
}
// 定义刷新回调
Future<void> _onRefresh() async {
// 模拟网络请求
await Future.delayed(const Duration(milliseconds: 500));
if (!mounted) return;
setState(() {
_items = _generateItems(150);
});
// 刷新成功后,重置加载状态,以便可以再次上拉加载
_controller.refreshCompleted();
}
// 定义加载回调
Future<void> _onLoading() async {
// 模拟网络请求
await Future.delayed(const Duration(milliseconds: 500));
if (!mounted) return;
final newItems = _generateItems(100, offset: _items.length);
setState(() {
_items.addAll(newItems);
});
// 使用控制器更新 Footer 状态
if (newItems.isEmpty || _items.length >= 1000) {
// 如果没有更多数据了
_controller.loadNoData();
} else {
// 加载成功
_controller.loadComplete();
}
}
@override
void dispose() {
// 销毁控制器
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('fluent_refresher demo')),
// 使用工厂函数构造
body: FluentRefresher.builder(
controller: _controller,
enablePullDown: true,
enablePullUp: true,
onRefresh: _onRefresh,
onLoading: _onLoading,
itemCount: _items.length,
itemBuilder: (context , index){
final item = _items[index];
return _buildCard(item);
},
),
// 普通构造函数
// body: FluentRefresher(
// controller: _controller,
// enablePullDown: true,
// enablePullUp: true,
// onRefresh: _onRefresh,
// onLoading: _onLoading,
// headerTriggerDistance: 40.0,
// sliver: SliverList(
// delegate: SliverChildBuilderDelegate((context, index) {
// final item = _items[index];
// return _buildCard(item);
// },
// childCount: _items.length,
// ),
// ),
// ),
);
}
Widget _buildCard(Map<String, dynamic> item){
return Card(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
elevation: 4,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.network(
item['imageUrl'],
width: 80,
height: 80,
fit: BoxFit.cover,
loadingBuilder: (context, child, progress) =>
progress == null ? child : const Center(child: CircularProgressIndicator()),
errorBuilder: (context, error, stackTrace) =>
const Icon(Icons.error, size: 40, color: Colors.red),
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(item['title'], style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
Text(item['subtitle'], style: Theme.of(context).textTheme.bodySmall),
],
),
),
],
),
),
);
}
}