az_listview.dart
5.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import 'package:flutter/material.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'az_common.dart';
import 'index_bar.dart';
import 'suspension_view.dart';
/// AzListView
class AzListView extends StatefulWidget {
const AzListView({
super.key,
required this.data,
required this.itemCount,
required this.itemBuilder,
this.itemScrollController,
this.itemPositionsListener,
this.physics,
this.padding,
this.susItemBuilder,
this.susItemHeight = kSusItemHeight,
this.susPosition,
this.indexHintBuilder,
this.indexBarData = kIndexBarData,
this.indexBarWidth = kIndexBarWidth,
this.indexBarHeight,
this.indexBarItemHeight = kIndexBarItemHeight,
this.hapticFeedback = false,
this.indexBarAlignment = Alignment.centerRight,
this.indexBarMargin,
this.indexBarOptions = const IndexBarOptions(),
});
/// with ISuspensionBean Data
final List<ISuspensionBean> data;
/// Number of items the [itemBuilder] can produce.
final int itemCount;
/// Called to build children for the list with
/// 0 <= index < itemCount.
final IndexedWidgetBuilder itemBuilder;
/// Controller for jumping or scrolling to an item.
final ItemScrollController? itemScrollController;
/// Notifier that reports the items laid out in the list after each frame.
final ItemPositionsListener? itemPositionsListener;
/// How the scroll view should respond to user input.
///
/// For example, determines how the scroll view continues to animate after the
/// user stops dragging the scroll view.
///
/// See [ScrollView.physics].
final ScrollPhysics? physics;
/// The amount of space by which to inset the children.
final EdgeInsets? padding;
/// Called to build suspension header.
final IndexedWidgetBuilder? susItemBuilder;
/// Suspension widget Height.
final double susItemHeight;
/// Suspension item position.
final Offset? susPosition;
/// IndexHintBuilder.
final IndexHintBuilder? indexHintBuilder;
/// Index data.
final List<String> indexBarData;
/// IndexBar Width.
final double indexBarWidth;
/// IndexBar Height.
final double? indexBarHeight;
/// IndexBar Item Height.
final double indexBarItemHeight;
/// Haptic feedback.
final bool hapticFeedback;
/// IndexBar alignment.
final AlignmentGeometry indexBarAlignment;
/// IndexBar margin.
final EdgeInsetsGeometry? indexBarMargin;
/// IndexBar options.
final IndexBarOptions indexBarOptions;
@override
createState() => _AzListViewState();
}
class _AzListViewState extends State<AzListView> {
/// Controller to scroll or jump to a particular item.
late ItemScrollController itemScrollController;
/// Listener that reports the position of items when the list is scrolled.
late ItemPositionsListener itemPositionsListener;
IndexBarDragListener dragListener = IndexBarDragListener.create();
final IndexBarController indexBarController = IndexBarController();
String selectTag = '';
@override
void initState() {
super.initState();
itemScrollController = widget.itemScrollController ?? ItemScrollController();
itemPositionsListener = widget.itemPositionsListener ?? ItemPositionsListener.create();
dragListener.dragDetails.addListener(_valueChanged);
if (widget.indexBarOptions.selectItemDecoration != null) {
itemPositionsListener.itemPositions.addListener(_positionsChanged);
}
}
@override
void dispose() {
super.dispose();
dragListener.dragDetails.removeListener(_valueChanged);
if (widget.indexBarOptions.selectItemDecoration != null) {
itemPositionsListener.itemPositions.removeListener(_positionsChanged);
}
}
int _getIndex(String tag) {
for (int i = 0; i < widget.itemCount; i++) {
ISuspensionBean bean = widget.data[i];
if (tag == bean.getSuspensionTag()) {
return i;
}
}
return -1;
}
void _scrollTopIndex(String tag) {
int index = _getIndex(tag);
if (index != -1) {
itemScrollController.jumpTo(index: index);
}
}
void _valueChanged() {
IndexBarDragDetails details = dragListener.dragDetails.value;
String tag = details.tag!;
if (details.action == IndexBarDragDetails.actionDown || details.action == IndexBarDragDetails.actionUpdate) {
selectTag = tag;
_scrollTopIndex(tag);
}
}
void _positionsChanged() {
Iterable<ItemPosition> positions = itemPositionsListener.itemPositions.value;
if (positions.isNotEmpty) {
ItemPosition itemPosition = positions.where((ItemPosition position) => position.itemTrailingEdge > 0).reduce(
(ItemPosition min, ItemPosition position) =>
position.itemTrailingEdge < min.itemTrailingEdge ? position : min);
int index = itemPosition.index;
String tag = widget.data[index].getSuspensionTag();
if (selectTag != tag) {
selectTag = tag;
indexBarController.updateTagIndex(tag);
}
}
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
SuspensionView(
data: widget.data,
itemCount: widget.itemCount,
itemBuilder: widget.itemBuilder,
itemScrollController: itemScrollController,
itemPositionsListener: itemPositionsListener,
susItemBuilder: widget.susItemBuilder,
susItemHeight: widget.susItemHeight,
susPosition: widget.susPosition,
padding: widget.padding,
physics: widget.physics,
),
Align(
alignment: widget.indexBarAlignment,
child: IndexBar(
data: widget.indexBarData,
width: widget.indexBarWidth,
height: widget.indexBarHeight,
itemHeight: widget.indexBarItemHeight,
margin: widget.indexBarMargin,
indexHintBuilder: widget.indexHintBuilder,
indexBarDragListener: dragListener,
options: widget.indexBarOptions,
controller: indexBarController,
),
),
],
);
}
}