Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I'm having a problem with ListController.animateToItem inside a child OverlayEntry suddenly calling OverlayEntry.remove. #65

Open
gbtb16 opened this issue Jul 16, 2024 · 5 comments · May be fixed by #76

Comments

@gbtb16
Copy link

gbtb16 commented Jul 16, 2024

Hi there!

I'm using version 0.4.1 of super_sliver_list.

I have a problem when using an OverlayEntry that has as a child a custom StatefulWidget, we can call it XComponent, which returns a set of items in a CustomScrollView, along with a SuperSliverList.builder.

In XComponent's initState, there is a controller that references an external ValueNotifier that changes when the user highlights an item. Once the highlight changes, it calls ListController.animateToItem to move to the item selected by the text or manually. Visually testing through the app, it's not possible to find the problem. It is seen in my unit tests when selecting an item with the Enter key or left mouse click, which in addition to selecting the item, automatically calls ListController.animateToItem and then closes the overlay and jumps to the next FocusNode.

In question, closing the overlay while selecting an item, which in turn calls ListController.animateToItem, is where the problem lies. The exception thrown is:

First error:

The following assertion was thrown while finalizing the widget tree:
ScrollableState#562f2(tickers: tracking 1 ticker, position:
ScrollPositionWithSingleContext#73217(offset: 0.0, range: 0.0..183.0, viewport: 213.0,
ScrollableState, ClampingScrollPhysics -> RangeMaintainingScrollPhysics, null,
ScrollDirection.idle), effective physics: ClampingScrollPhysics -> RangeMaintainingScrollPhysics)
was disposed with an active Ticker.
ScrollableState created a Ticker via its TickerProviderStateMixin, but at the time dispose() was
called on the mixin, that Ticker was still active. All Tickers must be disposed before calling
super.dispose().
Tickers used by AnimationControllers should be disposed by calling dispose() on the
AnimationController itself. Otherwise, the ticker will leak.
The offending ticker was:
  _WidgetTicker(created by ScrollableState#562f2)
  The stack trace when the _WidgetTicker was actually created was:
  #0      new Ticker.<anonymous closure> (package:flutter/src/scheduler/ticker.dart:71:40)
  #1      new Ticker (package:flutter/src/scheduler/ticker.dart:73:6)
  #2      new _WidgetTicker (package:flutter/src/widgets/ticker_provider.dart)
  #3      TickerProviderStateMixin.createTicker
  (package:flutter/src/widgets/ticker_provider.dart:296:34)
  #4      new AnimationController (package:flutter/src/animation/animation_controller.dart:265:21)
  #5      AnimateToItem.animate (package:super_sliver_list/src/animate_to_item.dart:37:24)

Second error:

══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown while notifying listeners for AnimationController:
SuperSliverMultiBoxAdaptorElement unmounted
'package:flutter/src/widgets/framework.dart':
Failed assertion: line 6280 pos 12: '_renderObject != null'

Either the assertion indicates an error in the framework itself, or we should provide substantially
more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.yml

When the exception was thrown, this was the stack:
#2      RenderObjectElement.renderObject (package:flutter/src/widgets/framework.dart:6280:12)
#3      SliverMultiBoxAdaptorElement.renderObject (package:flutter/src/widgets/sliver.dart:725:57)
#4      SuperSliverMultiBoxAdaptorElement.renderObject (package:super_sliver_list/src/element.dart:28:13)        
#5      SuperSliverMultiBoxAdaptorElement.getOffsetToReveal (package:super_sliver_list/src/element.dart:47:12)   
#6      ExtentManager.getOffsetToReveal (package:super_sliver_list/src/extent_manager.dart:171:21)
#7      AnimateToItem.animate.<anonymous closure> (package:super_sliver_list/src/animate_to_item.dart:47:42)     
#8      AnimationLocalListenersMixin.notifyListeners (package:flutter/src/animation/listener_helpers.dart:161:19)#9      AnimationController._tick (package:flutter/src/animation/animation_controller.dart:865:5)
#10     Ticker._tick (package:flutter/src/scheduler/ticker.dart:258:12)
#11     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1386:15)
#12     SchedulerBinding.handleBeginFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1233:11)
#13     _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:633:13)
#14     SchedulerBinding.handleBeginFrame (package:flutter/src/scheduler/binding.dart:1231:17)
#15     AutomatedTestWidgetsFlutterBinding.pump.<anonymous closure> (package:flutter_test/src/binding.dart:1265:9)
#18     TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:71:41)
#19     AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:1256:27)
#20     WidgetTester.pumpAndSettle.<anonymous closure> (package:flutter_test/src/widget_tester.dart:712:23)  

Third error:

══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
The following assertion was thrown while dispatching notifications for ValueNotifier<int?>:
ListController is not attached.
'package:super_sliver_list/src/super_sliver_list.dart':
Failed assertion: line 130 pos 12: '_delegate != null'

When the exception was thrown, this was the stack:
#2      ListController.animateToItem (package:super_sliver_list/src/super_sliver_list.dart:130:12)
#3      _AutocompleteV2OverlayConteudoItensState._scrollToHighlight (package:lib_flutter_drie/components_layout_v2/autocomplete_v2/components/autocomplete_v2_overlay_conteudo_itens.dart:101:21)
#4      _AutocompleteV2OverlayConteudoItensState._listener (package:lib_flutter_drie/components_layout_v2/autocomplete_v2/components/autocomplete_v2_overlay_conteudo_itens.dart:94:7)
#5      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:432:24)
#6      ValueNotifier.value= (package:flutter/src/foundation/change_notifier.dart:554:5)

All the highlighting logic has been tested and proven before, so this wouldn't be your problem.

Studying the case, I imagine the problem is that when an AnimateToItem is created, animate() is called immediately after, but these items are never actually disposed of, resulting in a malfunction when externally forced to exit the loop on its own.

super_sliver_list.dart at 122 line in animateToItem method.
image

animate_to_item.dart at 28 line in animate method.
image

@gbtb16 gbtb16 changed the title I'm having a problem with ListController.animateItem inside a child OverlayEntry suddenly calling OverlayEntry.remove. I'm having a problem with ListController.animateToItem inside a child OverlayEntry suddenly calling OverlayEntry.remove. Jul 16, 2024
@Zekfad
Copy link

Zekfad commented Jan 6, 2025

I'm facing same problem, but i'm using Autocomplete, which causes issues when there is running animation and widget get's removed (user changes text such that widget is removed).

@gbtb16 have you found workaround?

@Zekfad
Copy link

Zekfad commented Jan 6, 2025

I think the issue is that created animation controller is not disposed (leaked) here:

final controller = AnimationController(

@knopp
Copy link
Collaborator

knopp commented Jan 6, 2025

The control is disposed when animation is completed

if (status == AnimationStatus.completed) {
controller.dispose();
}

And also when the item is removed during animation

if (index == null) {
controller.stop();
controller.dispose();
return;
}

Is there a codepath where the controller is not disposed?

Zekfad added a commit to Zekfad/super_sliver_list that referenced this issue Jan 6, 2025
@Zekfad Zekfad linked a pull request Jan 6, 2025 that will close this issue
@Zekfad
Copy link

Zekfad commented Jan 6, 2025

@knopp I've made PR to address this, there is a code path when ListController is detached in mid-animation, which causes Ticker leak.

Animation also needs to be disposed (controller doesn't dispose animations).
Also index is user supplied, so its not really about index being removed, but user saying that it's removed (user has to say that index is no longer valid by returning null).

@gbtb16
Copy link
Author

gbtb16 commented Jan 8, 2025

Hi @Zekfad!

Thank you for your comment on my issue and the PR you submitted to try to solve this problem.

My temporary solution was to use the jumpToItem method instead of animateToItem to prevent the animation from happening.

This fixed the bug and produced a faster but less fluid UI since it's basically a teleport when you consider a rotating list using math modules.

I hope your contribution will be reviewed and merged!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants