@@ -145,6 +145,34 @@ class _FortuneBarState extends State<FortuneBar> with SingleTickerProviderStateM
145145 // animateFirst is only for initState
146146 }
147147
148+ double _getIndicatorWidth (
149+ Alignment alignment,
150+ double scrollOffset,
151+ List <double > itemWidths,
152+ double screenWidth,
153+ double totalWidth,
154+ ) {
155+ final centerOffset = screenWidth / 2 ;
156+ final P = scrollOffset % totalWidth;
157+ final relativeP = P < 0 ? P + totalWidth : P ;
158+
159+ final screenX = (alignment.x + 1) / 2 * screenWidth;
160+ final distFromCenter = screenX - centerOffset;
161+
162+ var stripPos = relativeP + distFromCenter;
163+ stripPos %= totalWidth;
164+ if (stripPos < 0) stripPos += totalWidth;
165+
166+ double currentPos = 0;
167+ for (final w in itemWidths) {
168+ if (stripPos < currentPos + w) {
169+ return w;
170+ }
171+ currentPos += w;
172+ }
173+ return itemWidths.isEmpty ? 0 : itemWidths.last;
174+ }
175+
148176 @override
149177 Widget build(BuildContext context) {
150178 final theme = Theme .of(context);
@@ -171,82 +199,76 @@ class _FortuneBarState extends State<FortuneBar> with SingleTickerProviderStateM
171199 final itemWidths = widget.items.map ((e) => e.weight * unitWidth).toList ();
172200 final totalWidth = totalWeight * unitWidth;
173201
174- return Stack (
175- children: [
176- AnimatedBuilder (
177- animation: _animationManager.animation,
178- builder: (context, _) {
179- // Calculate Target
180- final selectedIndex =
181- _animationManager.selectedIndex.value;
182- double targetCenterWeight = 0 ;
183- for (int i = 0 ; i < selectedIndex; i++ ) {
184- targetCenterWeight += widget.items[i].weight;
185- }
186- targetCenterWeight +=
187- widget.items[selectedIndex].weight / 2 ;
188-
189- final targetTotalScrollWeight =
190- widget.rotationCount * totalWeight +
191- targetCenterWeight;
192-
193- // Pan logic
194- // We want panning width/2 to correspond to 1 item (avg weight).
195- // panWeight = -dist * (2 * avgWeight / size.width)
196- final panWeight = - panState.distance *
197- (2 * avgWeight / size.width);
198-
199- final isAnimating =
200- _animationManager.controller.isAnimating;
201- final isAnimatingPanFactor = isAnimating ? 0 : 1 ;
202-
203- // Current Scroll Weight
204- final currentScrollWeight =
205- _animationManager.animation.value *
206- targetTotalScrollWeight +
207- panWeight * isAnimatingPanFactor;
208-
209- final scrollOffset = currentScrollWeight * unitWidth;
210-
211- return _InfiniteBar (
212- size: size,
213- scrollOffset: scrollOffset,
214- itemWidths: itemWidths,
215- totalWidth: totalWidth,
216- children: [
217- for (int i = 0 ; i < widget.items.length; i++ )
218- _FortuneBarItem (
219- item: widget.items[i],
220- style: widget.items[i].style ??
221- widget.styleStrategy.getItemStyle (
222- theme,
223- i,
224- widget.items.length,
225- ),
226- )
227- ],
228- );
229- }),
230- for (var it in widget.indicators)
231- IgnorePointer (
232- child: Align (
233- alignment: it.alignment,
234- child: SizedBox (
235- width: size.width / widget.visibleItemCount, // Indicator size assumes uniform?
236- // The user can customize indicator.
237- // Standard indicator assumes uniform items.
238- // Ideally indicator should match the item being pointed at?
239- // But in FortuneBar, indicator is usually fixed.
240- // If we have variable weights, the item under indicator has variable width.
241- // So the indicator width probably shouldn't depend on "visibleItemCount" if items vary?
242- // Or maybe it should just be a fixed size visual?
243- // "SizedBox(width: size.width / visibleItemCount)" makes indicator same size as "average item".
244- height: widget.height,
245- child: it.child,
246- ),
202+ return AnimatedBuilder (
203+ animation: _animationManager.animation,
204+ builder: (context, _) {
205+ // Calculate Target
206+ final selectedIndex = _animationManager.selectedIndex.value;
207+ double targetCenterWeight = 0 ;
208+ for (int i = 0 ; i < selectedIndex; i++ ) {
209+ targetCenterWeight += widget.items[i].weight;
210+ }
211+ targetCenterWeight += widget.items[selectedIndex].weight / 2 ;
212+
213+ final targetTotalScrollWeight =
214+ widget.rotationCount * totalWeight + targetCenterWeight;
215+
216+ // Pan logic
217+ // We want panning width/2 to correspond to 1 item (avg weight).
218+ // panWeight = -dist * (2 * avgWeight / size.width)
219+ final panWeight =
220+ - panState.distance * (2 * avgWeight / size.width);
221+
222+ final isAnimating = _animationManager.controller.isAnimating;
223+ final isAnimatingPanFactor = isAnimating ? 0 : 1 ;
224+
225+ // Current Scroll Weight
226+ final currentScrollWeight = _animationManager.animation.value *
227+ targetTotalScrollWeight +
228+ panWeight * isAnimatingPanFactor;
229+
230+ final scrollOffset = currentScrollWeight * unitWidth;
231+
232+ return Stack (
233+ children: [
234+ _InfiniteBar (
235+ size: size,
236+ scrollOffset: scrollOffset,
237+ itemWidths: itemWidths,
238+ totalWidth: totalWidth,
239+ children: [
240+ for (int i = 0 ; i < widget.items.length; i++ )
241+ _FortuneBarItem (
242+ item: widget.items[i],
243+ style: widget.items[i].style ??
244+ widget.styleStrategy.getItemStyle (
245+ theme,
246+ i,
247+ widget.items.length,
248+ ),
249+ )
250+ ],
247251 ),
248- ),
249- ],
252+ for (var it in widget.indicators)
253+ IgnorePointer (
254+ child: Align (
255+ alignment: it.alignment,
256+ child: SizedBox (
257+ width: _getIndicatorWidth (
258+ it.alignment.resolve (Directionality .of (context)),
259+ scrollOffset,
260+ itemWidths,
261+ size.width,
262+ totalWidth,
263+ ),
264+ height: widget.height,
265+ child: it.child,
266+ ),
267+ ),
268+ ),
269+ ],
270+ );
271+ },
250272 );
251273 });
252274 });
0 commit comments