Skip to content

Commit ede238f

Browse files
committed
Add fetch more example
1 parent 733f002 commit ede238f

File tree

6 files changed

+180
-14
lines changed

6 files changed

+180
-14
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
2+
import 'package:example/widgets/example_app_bar.dart';
3+
import 'package:flutter/material.dart';
4+
5+
class FetchMoreIndicator extends StatelessWidget {
6+
final Widget child;
7+
final VoidCallback onAction;
8+
9+
const FetchMoreIndicator({
10+
Key? key,
11+
required this.child,
12+
required this.onAction,
13+
}) : super(key: key);
14+
15+
@override
16+
Widget build(BuildContext context) {
17+
const height = 150.0;
18+
return CustomRefreshIndicator(
19+
onRefresh: () async => onAction(),
20+
reversed: true,
21+
trailingScrollIndicatorVisible: false,
22+
leadingScrollIndicatorVisible: true,
23+
child: child,
24+
builder: (
25+
BuildContext context,
26+
Widget child,
27+
IndicatorController controller,
28+
) {
29+
return AnimatedBuilder(
30+
animation: controller,
31+
builder: (context, _) {
32+
final dy = controller.value.clamp(0.0, 1.25) *
33+
-(height - (height * 0.25));
34+
return Stack(
35+
children: [
36+
Transform.translate(
37+
offset: Offset(0.0, dy),
38+
child: child,
39+
),
40+
Positioned(
41+
bottom: -height,
42+
left: 0,
43+
right: 0,
44+
height: height,
45+
child: Container(
46+
transform: Matrix4.translationValues(0.0, dy, 0.0),
47+
padding: const EdgeInsets.only(top: 30.0),
48+
constraints: const BoxConstraints.expand(),
49+
child: Column(
50+
children: [
51+
if (controller.isLoading)
52+
Container(
53+
margin: const EdgeInsets.only(bottom: 8.0),
54+
width: 16,
55+
height: 16,
56+
child: const CircularProgressIndicator(
57+
color: appContentColor,
58+
strokeWidth: 2,
59+
),
60+
)
61+
else
62+
const Icon(
63+
Icons.keyboard_arrow_up,
64+
color: appContentColor,
65+
),
66+
Text(
67+
controller.isLoading
68+
? "Fetching..."
69+
: "Pull to fetch more",
70+
style: const TextStyle(
71+
color: appContentColor,
72+
),
73+
)
74+
],
75+
),
76+
),
77+
),
78+
],
79+
);
80+
});
81+
},
82+
);
83+
}
84+
}

example/lib/main.dart

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
55

66
import 'indicators/simple_indicator.dart';
77
import 'screens/example_indicator_screen.dart';
8+
import 'screens/fetch_more_screen.dart';
89
import 'screens/ice_cream_indicator_screen.dart';
910
import 'screens/plane_indicator_screen.dart';
1011
import 'screens/check_mark_indicator_screen.dart';
@@ -29,10 +30,11 @@ class MyApp extends StatelessWidget {
2930
routes: {
3031
'/example': (context) => const ExampleIndicatorScreen(),
3132
'/plane': (context) => const PlaneIndicatorScreen(),
32-
'/ice_cream': (context) => const IceCreamIndicatorScreen(),
33+
'/ice-cream': (context) => const IceCreamIndicatorScreen(),
3334
'/presentation': (context) => const PresentationScreen(),
3435
'/check-mark': (context) => const CheckMarkIndicatorScreen(),
3536
'/warp': (context) => const WarpIndicatorScreen(),
37+
'/fetch-more': (context) => const FetchMoreScreen(),
3638
'/programmatically-controlled': (context) =>
3739
const ProgrammaticallyControlled(),
3840
},
@@ -57,7 +59,7 @@ class MainScreen extends StatelessWidget {
5759
child: Container(
5860
height: 50,
5961
alignment: Alignment.center,
60-
child: const Text("Presentation"),
62+
child: const Text("Controller presentation"),
6163
),
6264
onPressed: () => Navigator.pushNamed(
6365
context,
@@ -111,15 +113,15 @@ class MainScreen extends StatelessWidget {
111113
),
112114
onPressed: () => Navigator.pushNamed(
113115
context,
114-
'/ice_cream',
116+
'/ice-cream',
115117
),
116118
),
117119
const SizedBox(height: 15),
118120
ElevatedButton(
119121
child: Container(
120122
height: 50,
121123
alignment: Alignment.center,
122-
child: const Text("Check mark"),
124+
child: const Text("Witch complete state"),
123125
),
124126
onPressed: () => Navigator.pushNamed(
125127
context,
@@ -151,6 +153,18 @@ class MainScreen extends StatelessWidget {
151153
'/programmatically-controlled',
152154
),
153155
),
156+
const SizedBox(height: 15),
157+
ElevatedButton(
158+
child: Container(
159+
height: 50,
160+
alignment: Alignment.center,
161+
child: const Text("Swipe to fetch more"),
162+
),
163+
onPressed: () => Navigator.pushNamed(
164+
context,
165+
'/fetch-more',
166+
),
167+
),
154168
],
155169
),
156170
),
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import 'package:example/indicators/swipe_action.dart';
2+
import 'package:example/widgets/example_app_bar.dart';
3+
import 'package:example/widgets/example_list.dart';
4+
import 'package:flutter/material.dart';
5+
6+
class FetchMoreScreen extends StatefulWidget {
7+
const FetchMoreScreen({Key? key}) : super(key: key);
8+
9+
@override
10+
State<FetchMoreScreen> createState() => _FetchMoreScreenState();
11+
}
12+
13+
class _FetchMoreScreenState extends State<FetchMoreScreen> {
14+
int _itemsCount = 10;
15+
16+
Future<void> _fetchMore() async {
17+
// Simulate fetch time
18+
await Future<void>.delayed(const Duration(seconds: 2));
19+
// make sure that the widget is still mounted.
20+
if (!mounted) return;
21+
// Add more fake elements
22+
setState(() {
23+
_itemsCount += 10;
24+
});
25+
}
26+
27+
@override
28+
Widget build(BuildContext context) {
29+
return Scaffold(
30+
appBar: const ExampleAppBar(title: "Scroll to fetch more"),
31+
body: FetchMoreIndicator(
32+
child: ExampleList(
33+
itemCount: _itemsCount,
34+
countElements: true,
35+
),
36+
onAction: _fetchMore,
37+
),
38+
);
39+
}
40+
}

example/lib/screens/programmatically_controlled_indicator_screen.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:math';
22

33
import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
44
import 'package:example/indicators/warp_indicator.dart';
5+
import 'package:example/widgets/example_app_bar.dart';
56
import 'package:example/widgets/example_list.dart';
67
import 'package:flutter/material.dart';
78

@@ -33,8 +34,8 @@ class _ProgrammaticallyControlledState
3334
@override
3435
Widget build(BuildContext context) {
3536
return Scaffold(
36-
appBar: AppBar(
37-
title: const Text("Programmatically-controlled"),
37+
appBar: ExampleAppBar(
38+
title: "Programmatically-controlled",
3839
actions: [
3940
AnimatedBuilder(
4041
animation: controller,

example/lib/widgets/example_app_bar.dart

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import 'package:flutter/material.dart';
22

33
const appBackgroundColor = Color(0xFFf8f4fc);
4+
const appContentColor = Color(0xff877162);
45

56
class ExampleAppBar extends StatelessWidget implements PreferredSizeWidget {
6-
const ExampleAppBar({Key? key}) : super(key: key);
7+
final String? title;
8+
final List<Widget>? actions;
9+
10+
const ExampleAppBar({
11+
Key? key,
12+
this.title,
13+
this.actions,
14+
}) : super(key: key);
715

816
@override
917
Widget build(BuildContext context) {
@@ -12,12 +20,13 @@ class ExampleAppBar extends StatelessWidget implements PreferredSizeWidget {
1220
color: Color(0xff877162),
1321
),
1422
backgroundColor: appBackgroundColor,
15-
title: const Text(
16-
"flutter_custom_refresh_indicator",
17-
style: TextStyle(
18-
color: Color(0xff877162),
23+
title: Text(
24+
title ?? "flutter_custom_refresh_indicator",
25+
style: const TextStyle(
26+
color: appContentColor,
1927
),
2028
),
29+
actions: actions,
2130
elevation: 3,
2231
);
2332
}

example/lib/widgets/example_list.dart

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import 'example_app_bar.dart';
44

55
class ExampleList extends StatelessWidget {
66
final int itemCount;
7+
final bool countElements;
78

89
final Color backgroundColor;
910
const ExampleList({
1011
Key? key,
12+
this.countElements = false,
1113
this.backgroundColor = appBackgroundColor,
1214
this.itemCount = 4,
1315
}) : super(key: key);
@@ -30,7 +32,18 @@ class ExampleList extends StatelessWidget {
3032
physics: const AlwaysScrollableScrollPhysics(
3133
parent: ClampingScrollPhysics(),
3234
),
33-
itemBuilder: (BuildContext context, int index) => const Element(),
35+
itemBuilder: (BuildContext context, int index) => countElements
36+
? Element(
37+
child: Center(
38+
child: Text(
39+
"${index + 1}",
40+
style: const TextStyle(
41+
color: appContentColor,
42+
),
43+
),
44+
),
45+
)
46+
: const Element(),
3447
itemCount: itemCount,
3548
separatorBuilder: (BuildContext context, int index) => const Divider(
3649
height: 0,
@@ -43,7 +56,9 @@ class ExampleList extends StatelessWidget {
4356
}
4457

4558
class Element extends StatelessWidget {
46-
const Element({Key? key}) : super(key: key);
59+
final Widget? child;
60+
61+
const Element({Key? key, this.child}) : super(key: key);
4762

4863
@override
4964
Widget build(BuildContext context) {
@@ -53,7 +68,7 @@ class Element extends StatelessWidget {
5368
child: Row(
5469
crossAxisAlignment: CrossAxisAlignment.start,
5570
children: <Widget>[
56-
const FakeBox(height: 80, width: 80),
71+
FakeBox(height: 80, width: 80, child: child),
5772
const SizedBox(width: 20),
5873
Expanded(
5974
child: Column(
@@ -74,10 +89,12 @@ class Element extends StatelessWidget {
7489
}
7590

7691
class FakeBox extends StatelessWidget {
92+
final Widget? child;
7793
const FakeBox({
7894
Key? key,
7995
required this.width,
8096
required this.height,
97+
this.child,
8198
}) : super(key: key);
8299

83100
final double width;
@@ -97,6 +114,7 @@ class FakeBox extends StatelessWidget {
97114
width: width,
98115
height: height,
99116
decoration: _boxDecoration,
117+
child: child,
100118
);
101119
}
102120
}

0 commit comments

Comments
 (0)