diff --git a/tests/app/ui/list-view/list-view-tests.ts b/tests/app/ui/list-view/list-view-tests.ts index 400b8c488..5f0e1ef25 100644 --- a/tests/app/ui/list-view/list-view-tests.ts +++ b/tests/app/ui/list-view/list-view-tests.ts @@ -759,6 +759,33 @@ export class ListViewTest extends UITest { TKUnit.assertEqual(lastNativeElementVisible, false, "Last element is not visible"); } + public test_scrollToIndex_should_coerce_negative_index_to_zero_index() { + var listView = this.testView; + + listView.items = MANY_ITEMS; + listView.scrollToIndex(-1); + TKUnit.wait(0.1); + + var firstNativeElementVisible = this.checkItemVisibleAtIndex(listView, 0); + TKUnit.assertEqual(firstNativeElementVisible, true, "first element is visible"); + } + + public test_scrollToIndex_should_coerce_larger_index_to_last_item_index() { + var listView = this.testView; + + listView.items = MANY_ITEMS; + listView.scrollToIndex(10000); + TKUnit.wait(0.1); + + var lastNativeElementVisible = this.checkItemVisibleAtIndex(listView, MANY_ITEMS.length - 1); + TKUnit.assertEqual(lastNativeElementVisible, true, "last element is visible"); + } + + public test_scrollToIndex_should_not_throw_if_items_not_set() { + var listView = this.testView; + listView.scrollToIndex(10000); + } + private checkItemVisibleAtIndex(listView: ListView, index: number): boolean { return listView.isItemAtIndexVisible(index); } diff --git a/tns-core-modules/ui/list-view/list-view.ios.ts b/tns-core-modules/ui/list-view/list-view.ios.ts index 5775d236a..ed2a89d00 100644 --- a/tns-core-modules/ui/list-view/list-view.ios.ts +++ b/tns-core-modules/ui/list-view/list-view.ios.ts @@ -1,4 +1,4 @@ -import { ItemEventData } from "."; +import { ItemEventData } from "."; import { ListViewBase, View, KeyedTemplate, Length, Observable, Color, separatorColorProperty, itemTemplatesProperty, iosEstimatedRowHeightProperty, layout, EventData @@ -6,6 +6,7 @@ import { import { StackLayout } from "../layouts/stack-layout"; import { ProxyViewContainer } from "../proxy-view-container"; import { profile } from "../../profiling"; +import * as trace from "../../trace"; export * from "./list-view-common"; @@ -261,16 +262,31 @@ export class ListView extends ListViewBase { } public scrollToIndex(index: number) { - if (this._ios) { - this._ios.scrollToRowAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(index, 0), - UITableViewScrollPosition.Top, false); - } + this._scrollToIndex(index, false); } public scrollToIndexAnimated(index: number) { - if (this._ios) { + this._scrollToIndex(index); + } + + private _scrollToIndex(index: number, animated: boolean = true) { + if (!this._ios) { + return; + } + + const itemsLength = this.items ? this.items.length : 0; + // mimic Android behavior that silently coerces index values within [0, itemsLength - 1] range + if (itemsLength > 0) { + if (index < 0) { + index = 0 + } else if (index >= itemsLength) { + index = itemsLength - 1; + } + this._ios.scrollToRowAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(index, 0), - UITableViewScrollPosition.Top, true); + UITableViewScrollPosition.Top, animated); + } else if (trace.isEnabled()) { + trace.write(`Cannot scroll listview to index ${index} when listview items not set`, trace.categories.Binding); } }