diff --git a/CHANGELOG.md b/CHANGELOG.md index 7790c6d..0fc1cdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # CHANGES +**3.0.2** +* Fixed issues with scrolling in lists with AutomaticKeepAliveClientMixin item widgets + **3.0.1** * #94: Why can't forecast the move range when moveTarget is negative? diff --git a/lib/scroll_to_index.dart b/lib/scroll_to_index.dart index 7b37c6b..1a6045f 100644 --- a/lib/scroll_to_index.dart +++ b/lib/scroll_to_index.dart @@ -396,7 +396,49 @@ mixin AutoScrollControllerMixin on ScrollController ..sort((int first, int second) => first.compareTo(second)); final min = sorted.first; final max = sorted.last; - return (index - min).abs() < (index - max).abs() ? min : max; + + if (index > min && index < max) { + return _getNearestIndexFromCurrentOffset(index, sorted); + } else { + return (index - min).abs() < (index - max).abs() ? min : max; + } + } + + /// Returns the nearest item index to the given [index] from the list of + /// [storedItemIndexes]. If two finds to equally close indexes, returns the + /// one with the smaller distance to current offset. + int _getNearestIndexFromCurrentOffset( + int index, + List storedItemIndexes, + ) { + int closestIndex = storedItemIndexes.first; + for (final storedIndex in storedItemIndexes) { + final differenceWithIndex = (storedIndex - index).abs(); + final differenceWithLastClosestIndex = (closestIndex - index).abs(); + if (differenceWithIndex < differenceWithLastClosestIndex) { + closestIndex = storedIndex; + } else if (differenceWithIndex == differenceWithLastClosestIndex) { + final distanceToLastClosestIndex = _distanceToItem(closestIndex); + final distanceToStoredIndex = _distanceToItem(storedIndex); + if (distanceToStoredIndex != null && + distanceToLastClosestIndex != null && + distanceToStoredIndex < distanceToLastClosestIndex) { + closestIndex = storedIndex; + } + } + } + return closestIndex; + } + + /// returns the distance between the current offset and the offset of the item + /// at the given [index]. + double? _distanceToItem(int index) { + final itemOffset = _offsetToRevealInViewport(index, 0.5)?.offset; + if (itemOffset == null) { + return null; + } + + return (offset - itemOffset).abs(); } /// bring the state node (already created but all of it may not be fully in the viewport) into viewport @@ -477,9 +519,8 @@ mixin AutoScrollControllerMixin on ScrollController if (ctx == null) return null; final renderBox = ctx.findRenderObject()!; - assert(Scrollable.of(ctx) != null); final RenderAbstractViewport viewport = - RenderAbstractViewport.of(renderBox)!; + RenderAbstractViewport.of(renderBox); final revealedOffset = viewport.getOffsetToReveal(renderBox, alignment); return revealedOffset; diff --git a/pubspec.lock b/pubspec.lock index 50a1f04..9a7c5d7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,51 +5,50 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" source: hosted - version: "2.8.2" + version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" source: hosted - version: "1.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "1.3.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.18.0" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.1" flutter: dependency: "direct main" description: flutter @@ -60,34 +59,62 @@ packages: description: flutter source: sdk version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" source: hosted - version: "0.12.11" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - url: "https://pub.dartlang.org" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" source: hosted - version: "0.1.4" + version: "0.8.0" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + url: "https://pub.dev" source: hosted - version: "1.7.0" + version: "1.11.0" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" source: hosted - version: "1.8.1" + version: "1.9.0" sky_engine: dependency: transitive description: flutter @@ -97,51 +124,66 @@ packages: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.0" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + url: "https://pub.dev" source: hosted - version: "0.4.9" + version: "0.6.1" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=3.2.0-0 <4.0.0" flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 350e42b..2381bbc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: scroll_to_index description: Scroll to a specific child of any scrollable widget in Flutter -version: 3.0.1 +version: 3.0.2 homepage: https://github.com/quire-io/scroll-to-index environment: sdk: '>=2.12.0 <3.0.0'