1
- import 'package:azlistview_plus/azlistview_plus.dart' ;
2
1
import 'package:collection/collection.dart' ;
3
2
import 'package:flutter/material.dart' ;
4
3
import 'package:flutter_bloc/flutter_bloc.dart' ;
5
4
import 'package:kitchenowl/cubits/recipe_list_cubit.dart' ;
6
5
import 'package:kitchenowl/kitchenowl.dart' ;
6
+ import 'package:kitchenowl/widgets/index_bar.dart' ;
7
7
import 'package:kitchenowl/widgets/choice_scroll.dart' ;
8
8
import 'package:kitchenowl/widgets/recipe_card.dart' ;
9
9
import 'package:kitchenowl/widgets/recipe_item.dart' ;
@@ -17,16 +17,42 @@ class RecipeListPage extends StatefulWidget {
17
17
18
18
class _RecipeListPageState extends State <RecipeListPage > {
19
19
final TextEditingController searchController = TextEditingController ();
20
+ late final IndexScrollController scrollController;
21
+ final headerKey = GlobalKey ();
22
+
23
+ double getRowHeight () {
24
+ if (! mounted) return 1 ;
25
+ if (BlocProvider .of <RecipeListCubit >(context).state.listView) return 56 ;
26
+ return ((headerKey.currentContext! .size! .width - 16 - 32 ) / getRowCount ()) /
27
+ 0.8 ;
28
+ }
29
+
30
+ double getHeaderHeight () {
31
+ return headerKey.currentContext! .size! .height;
32
+ }
33
+
34
+ int getRowCount () {
35
+ if (! mounted) return 1 ;
36
+ if (BlocProvider .of <RecipeListCubit >(context).state.listView) return 1 ;
37
+ // header width - list padding
38
+ return ((headerKey.currentContext! .size! .width - 16 - 32 ) / 350 ).ceil ();
39
+ }
20
40
21
41
@override
22
42
void initState () {
23
43
super .initState ();
24
44
searchController.text = BlocProvider .of <RecipeListCubit >(context).query;
45
+ scrollController = IndexScrollController (
46
+ getRowHeight: getRowHeight,
47
+ getHeaderHeight: getHeaderHeight,
48
+ getItemRowCount: getRowCount,
49
+ );
25
50
}
26
51
27
52
@override
28
53
void dispose () {
29
54
searchController.dispose ();
55
+ scrollController.dispose ();
30
56
super .dispose ();
31
57
}
32
58
@@ -79,11 +105,13 @@ class _RecipeListPageState extends State<RecipeListPage> {
79
105
state.tags.isEmpty ||
80
106
state is SearchRecipeListState ) {
81
107
header = Align (
108
+ key: headerKey,
82
109
alignment: Alignment .topRight,
83
110
child: header,
84
111
);
85
112
} else {
86
113
header = Align (
114
+ key: headerKey,
87
115
alignment: Alignment .centerLeft,
88
116
child: Padding (
89
117
padding: const EdgeInsets .only (bottom: 6 ),
@@ -173,87 +201,70 @@ class _RecipeListPageState extends State<RecipeListPage> {
173
201
);
174
202
}
175
203
176
- Widget child;
177
- if (state.listView) {
178
- child = AzListView (
179
- itemCount: recipes.length + 1 ,
180
- data: < ISuspensionBean > [
181
- _HeaderBean (recipes.first.getSuspensionTag ())
182
- ] +
183
- recipes,
184
- indexBarData: SuspensionUtil .getTagIndexList (recipes),
185
- indexBarAlignment: Alignment .centerLeft,
186
- indexBarOptions: IndexBarOptions (
187
- needRebuild: true ,
188
- selectTextStyle: const TextStyle (
189
- fontWeight: FontWeight .bold,
190
- ),
191
- selectItemDecoration: const BoxDecoration (),
192
- indexHintWidth: 50 ,
193
- indexHintHeight: 50 ,
194
- indexHintDecoration: BoxDecoration (
195
- shape: BoxShape .circle,
196
- color: Theme .of (context)
197
- .colorScheme
198
- .primary
199
- .withAlpha (0xFF ),
200
- boxShadow: const [
201
- BoxShadow (
202
- color: Colors .black54,
203
- offset: Offset (1 , 1 ),
204
- blurRadius: 6 ,
205
- spreadRadius: - 2 ,
204
+ return RefreshIndicator (
205
+ onRefresh: cubit.refresh,
206
+ child: Stack (
207
+ children: [
208
+ CustomScrollView (
209
+ controller: scrollController,
210
+ slivers: [
211
+ SliverToBoxAdapter (child: header),
212
+ SliverPadding (
213
+ padding: const EdgeInsets .only (left: 32 , right: 16 ),
214
+ sliver: state.listView
215
+ ? SliverList (
216
+ delegate: SliverChildBuilderDelegate (
217
+ (context, i) => RecipeItemWidget (
218
+ recipe: recipes[i],
219
+ onUpdated: cubit.refresh,
220
+ ),
221
+ childCount: recipes.length,
222
+ ),
223
+ )
224
+ : SliverGrid .builder (
225
+ itemCount: recipes.length,
226
+ gridDelegate:
227
+ const SliverGridDelegateWithMaxCrossAxisExtent (
228
+ maxCrossAxisExtent: 350 ,
229
+ childAspectRatio: 0.8 ,
230
+ ),
231
+ itemBuilder: (context, i) => RecipeCard (
232
+ key: Key (recipes[i].name),
233
+ recipe: recipes[i],
234
+ onUpdated: cubit.refresh,
235
+ ),
236
+ ),
206
237
),
207
238
],
208
239
),
209
- indexHintTextStyle: TextStyle (
210
- fontSize: 20 ,
211
- color: Theme .of (context).colorScheme.onPrimary,
212
- ),
213
- indexHintAlignment: Alignment .centerLeft,
214
- ),
215
- hapticFeedback: true ,
216
- itemBuilder: (context, i) {
217
- if (i == 0 ) return header;
218
- i-- ;
219
- return Padding (
220
- key: Key (recipes[i].name),
221
- padding: const EdgeInsets .only (left: 32 , right: 16 ),
222
- child: RecipeItemWidget (
223
- recipe: recipes[i],
224
- onUpdated: cubit.refresh,
225
- ),
226
- );
227
- },
228
- );
229
- } else {
230
- child = CustomScrollView (
231
- primary: true ,
232
- slivers: [
233
- SliverToBoxAdapter (child: header),
234
- SliverPadding (
235
- padding: const EdgeInsets .symmetric (horizontal: 16 ),
236
- sliver: SliverGrid .builder (
237
- itemCount: recipes.length,
238
- gridDelegate:
239
- const SliverGridDelegateWithMaxCrossAxisExtent (
240
- maxCrossAxisExtent: 350 ,
241
- childAspectRatio: 0.8 ,
240
+ Align (
241
+ alignment: Alignment .centerLeft,
242
+ child: IndexBar (
243
+ controller: scrollController,
244
+ names: recipes.map ((r) => r.name).toList (),
245
+ indexHintDecoration: BoxDecoration (
246
+ shape: BoxShape .circle,
247
+ color: Theme .of (context)
248
+ .colorScheme
249
+ .primary
250
+ .withAlpha (0xFF ),
251
+ boxShadow: const [
252
+ BoxShadow (
253
+ color: Colors .black54,
254
+ offset: Offset (1 , 1 ),
255
+ blurRadius: 6 ,
256
+ spreadRadius: - 2 ,
257
+ ),
258
+ ],
242
259
),
243
- itemBuilder: (context, i) => RecipeCard (
244
- key: Key (recipes[i].name),
245
- recipe: recipes[i],
246
- onUpdated: cubit.refresh,
260
+ indexHintTextStyle: TextStyle (
261
+ fontSize: 20 ,
262
+ color: Theme .of (context).colorScheme.onPrimary,
247
263
),
248
264
),
249
265
),
250
266
],
251
- );
252
- }
253
-
254
- return RefreshIndicator (
255
- onRefresh: cubit.refresh,
256
- child: child,
267
+ ),
257
268
);
258
269
},
259
270
),
@@ -263,18 +274,3 @@ class _RecipeListPageState extends State<RecipeListPage> {
263
274
);
264
275
}
265
276
}
266
-
267
- class _HeaderBean implements ISuspensionBean {
268
- String suspensionTag;
269
-
270
- _HeaderBean (this .suspensionTag);
271
-
272
- @override
273
- bool get isShowSuspension => true ;
274
-
275
- @override
276
- String getSuspensionTag () => suspensionTag;
277
-
278
- @override
279
- set isShowSuspension (bool _isShowSuspension) {}
280
- }
0 commit comments