Skip to content

Commit ca6cccb

Browse files
manoldonevvakrilov
authored andcommitted
fix(ios): listview scrollToIndex crash with async data (#6182)
1 parent 040781c commit ca6cccb

2 files changed

Lines changed: 50 additions & 7 deletions

File tree

tests/app/ui/list-view/list-view-tests.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,33 @@ export class ListViewTest extends UITest<ListView> {
759759
TKUnit.assertEqual(lastNativeElementVisible, false, "Last element is not visible");
760760
}
761761

762+
public test_scrollToIndex_should_coerce_negative_index_to_zero_index() {
763+
var listView = this.testView;
764+
765+
listView.items = MANY_ITEMS;
766+
listView.scrollToIndex(-1);
767+
TKUnit.wait(0.1);
768+
769+
var firstNativeElementVisible = this.checkItemVisibleAtIndex(listView, 0);
770+
TKUnit.assertEqual(firstNativeElementVisible, true, "first element is visible");
771+
}
772+
773+
public test_scrollToIndex_should_coerce_larger_index_to_last_item_index() {
774+
var listView = this.testView;
775+
776+
listView.items = MANY_ITEMS;
777+
listView.scrollToIndex(10000);
778+
TKUnit.wait(0.1);
779+
780+
var lastNativeElementVisible = this.checkItemVisibleAtIndex(listView, MANY_ITEMS.length - 1);
781+
TKUnit.assertEqual(lastNativeElementVisible, true, "last element is visible");
782+
}
783+
784+
public test_scrollToIndex_should_not_throw_if_items_not_set() {
785+
var listView = this.testView;
786+
listView.scrollToIndex(10000);
787+
}
788+
762789
private checkItemVisibleAtIndex(listView: ListView, index: number): boolean {
763790
return listView.isItemAtIndexVisible(index);
764791
}

tns-core-modules/ui/list-view/list-view.ios.ts

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { ItemEventData } from ".";
1+
import { ItemEventData } from ".";
22
import {
33
ListViewBase, View, KeyedTemplate, Length, Observable, Color,
44
separatorColorProperty, itemTemplatesProperty, iosEstimatedRowHeightProperty, layout, EventData
55
} from "./list-view-common";
66
import { StackLayout } from "../layouts/stack-layout";
77
import { ProxyViewContainer } from "../proxy-view-container";
88
import { profile } from "../../profiling";
9+
import * as trace from "../../trace";
910

1011
export * from "./list-view-common";
1112

@@ -261,16 +262,31 @@ export class ListView extends ListViewBase {
261262
}
262263

263264
public scrollToIndex(index: number) {
264-
if (this._ios) {
265-
this._ios.scrollToRowAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(index, 0),
266-
UITableViewScrollPosition.Top, false);
267-
}
265+
this._scrollToIndex(index, false);
268266
}
269267

270268
public scrollToIndexAnimated(index: number) {
271-
if (this._ios) {
269+
this._scrollToIndex(index);
270+
}
271+
272+
private _scrollToIndex(index: number, animated: boolean = true) {
273+
if (!this._ios) {
274+
return;
275+
}
276+
277+
const itemsLength = this.items ? this.items.length : 0;
278+
// mimic Android behavior that silently coerces index values within [0, itemsLength - 1] range
279+
if (itemsLength > 0) {
280+
if (index < 0) {
281+
index = 0
282+
} else if (index >= itemsLength) {
283+
index = itemsLength - 1;
284+
}
285+
272286
this._ios.scrollToRowAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(index, 0),
273-
UITableViewScrollPosition.Top, true);
287+
UITableViewScrollPosition.Top, animated);
288+
} else if (trace.isEnabled()) {
289+
trace.write(`Cannot scroll listview to index ${index} when listview items not set`, trace.categories.Binding);
274290
}
275291
}
276292

0 commit comments

Comments
 (0)