Skip to content

Commit ac36729

Browse files
committed
The unloaded event of view in the ListView's itemTemplate will now be called when its underlying native view is removed from the visual tree. When this happens is beyond our control.
1 parent a4d879f commit ac36729

File tree

9 files changed

+199
-1
lines changed

9 files changed

+199
-1
lines changed

CrossPlatformModules.csproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@
7878
</TypeScriptCompile>
7979
<TypeScriptCompile Include="apps\action-bar-demo\pages\data-binding.ts">
8080
<DependentUpon>data-binding.xml</DependentUpon>
81+
<TypeScriptCompile Include="apps\list-view-demo\app.ts" />
82+
<TypeScriptCompile Include="apps\list-view-demo\main-page.ts">
83+
<DependentUpon>main-page.xml</DependentUpon>
8184
</TypeScriptCompile>
8285
<TypeScriptCompile Include="apps\cuteness.unoptimized\app.ts" />
8386
<TypeScriptCompile Include="apps\cuteness.unoptimized\details-page.ts">
@@ -94,6 +97,12 @@
9497
<Content Include="apps\action-bar-demo\pages\center-view-segmented.xml" />
9598
<Content Include="apps\action-bar-demo\pages\center-view.xml" />
9699
<Content Include="apps\action-bar-demo\pages\data-binding.xml" />
100+
<Content Include="apps\list-view-demo\another-page.xml">
101+
<SubType>Designer</SubType>
102+
</Content>
103+
<Content Include="apps\list-view-demo\main-page.xml">
104+
<SubType>Designer</SubType>
105+
</Content>
97106
<Content Include="apps\cuteness.unoptimized\reddit-item-view-model.ts" />
98107
<TypeScriptCompile Include="apps\cuteness.unoptimized\reddit-model.d.ts" />
99108
<TypeScriptCompile Include="apps\action-bar-demo\app.ts" />
@@ -1675,6 +1684,9 @@
16751684
<Content Include="apps\action-bar-demo\package.json" />
16761685
<Content Include="fetch\package.json" />
16771686
<Content Include="fetch\README.md" />
1687+
<Content Include="apps\list-view-demo\package.json">
1688+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
1689+
</Content>
16781690
<None Include="js-libs\esprima\LICENSE.BSD" />
16791691
<Content Include="source-control.md" />
16801692
<Content Include="ui\segmented-bar\package.json">
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<Page xmlns="http://www.nativescript.org/tns.xsd">
2+
<Label text="Another page"/>
3+
</Page>

apps/list-view-demo/app.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import application = require("application");
2+
application.mainModule = "main-page";
3+
application.start();

apps/list-view-demo/main-page.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import frame = require("ui/frame");
2+
import observableArray = require("data/observable-array");
3+
4+
var loaded = 0;
5+
var unloaded = 0;
6+
7+
var listView;
8+
var textField;
9+
10+
export function onNavigatedTo(args) {
11+
print();
12+
}
13+
14+
export function onTextFieldLoaded(args) {
15+
textField = args.object;
16+
}
17+
18+
export function onListViewLoaded(args) {
19+
listView = args.object;
20+
console.log("ListView LOADED.");
21+
print();
22+
onBind();
23+
}
24+
25+
export function onListViewUnloaded(args) {
26+
console.log("ListView UNLOADED.");
27+
print();
28+
}
29+
30+
export function onBind() {
31+
var length = textField.text;
32+
console.log("Bind to " + length + " items");
33+
var items = new observableArray.ObservableArray<string>();
34+
var i = 0;
35+
for (; i < length; i++) {
36+
items.push("Item " + i);
37+
}
38+
listView.items = items;
39+
print();
40+
}
41+
42+
export function onAdd() {
43+
var length = textField.text;
44+
console.log("Add " + length + " items");
45+
var i = 0;
46+
for (; i < length; i++) {
47+
var newItem = "Item " + (<observableArray.ObservableArray<string>>listView.items).length;
48+
(<observableArray.ObservableArray<string>>listView.items).push(newItem);
49+
}
50+
print();
51+
}
52+
53+
export function onRemove(s) {
54+
var length = textField.text;
55+
console.log("Remove " + length + " items");
56+
var i = 0;
57+
for (; i < length; i++) {
58+
(<observableArray.ObservableArray<string>>listView.items).splice((<observableArray.ObservableArray<string>>listView.items).length - 1);
59+
}
60+
print();
61+
}
62+
63+
export function onRefresh() {
64+
console.log("Refresh");
65+
listView.refresh();
66+
print();
67+
}
68+
69+
export function onNavigate() {
70+
console.log("Navigate");
71+
frame.topmost().navigate({ moduleName: "./another-page" });
72+
print();
73+
}
74+
75+
export function onViewLoaded(args) {
76+
loaded++;
77+
console.log(args.object.id + args.object._domId + " LOADED");
78+
}
79+
80+
export function onViewUnloaded(args) {
81+
unloaded++;
82+
console.log(args.object.id + args.object._domId + " UNLOADED");
83+
}
84+
85+
export function print() {
86+
console.log("L/U: " + loaded + "/" + unloaded);
87+
}

apps/list-view-demo/main-page.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Page xmlns="http://www.nativescript.org/tns.xsd" navigatedTo="onNavigatedTo">
2+
<StackLayout>
3+
<TextField text="1" loaded="onTextFieldLoaded"/>
4+
<Button text="Bind" tap="onBind"/>
5+
<Button text="Add" tap="onAdd"/>
6+
<Button text="Remove" tap="onRemove"/>
7+
<Button text="Refresh" tap="onRefresh"/>
8+
<Button text="Navigate" tap="onNavigate"/>
9+
<ListView loaded="onListViewLoaded" unloaded="onListViewUnloaded">
10+
<ListView.itemTemplate>
11+
<Label text="{{ $value }}" id="label" loaded="onViewLoaded" unloaded="onViewUnloaded" />
12+
</ListView.itemTemplate>
13+
</ListView>
14+
</StackLayout>
15+
</Page>

apps/list-view-demo/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{ "name" : "list-view-demo",
2+
"main" : "app.js" }

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,3 +684,43 @@ function performNativeItemTap(listView: listViewModule.ListView, index: number):
684684
throw new Error("Cannot perform native item tap");
685685
}
686686
}
687+
688+
//export function test_LoadedUnloaded() {
689+
// var listView = new listViewModule.ListView();
690+
// var vm = {
691+
// loadedCount: 0,
692+
// unloadedCount: 0,
693+
// onViewLoaded: function onViewLoaded(args) {
694+
// this.loadedCount++;
695+
// console.log(args.object._domId + " LOADED");
696+
// },
697+
// onViewUnloaded: function onViewUnloaded(args) {
698+
// this.unloadedCount++;
699+
// console.log(args.object._domId + " UNLOADED");
700+
// }
701+
// };
702+
// listView.itemTemplate = "<Label text=\"{{ $value }}\" loaded=\"{{ onViewLoaded }}\" unloaded=\"{{ onViewUnloaded }}\"/>";
703+
// listView.bindingContext = vm;
704+
705+
// var count = 10;
706+
// var modifier = listView.ios ? 1 : 0; // iOS has one fake measure cell that raises loaded.
707+
// var generate = function (count: number): observableArray.ObservableArray<string> {
708+
// var items = new observableArray.ObservableArray<string>();
709+
// for (var i = 0; i < count; i++) {
710+
// items.push("Item " + i);
711+
// }
712+
// return items;
713+
// }
714+
715+
// function testAction(views: Array<viewModule.View>) {
716+
// listView.items = generate(count);
717+
// TKUnit.wait(ASYNC);
718+
// frame.topmost().navigate("pages/navigation/pageB");
719+
// TKUnit.wait(ASYNC);
720+
// frame.topmost().goBack();
721+
// TKUnit.assertEqual(vm.loadedCount, count + modifier, "Loaded Count");
722+
// TKUnit.assertEqual(vm.unloadedCount, count, "Unloaded Count");
723+
// }
724+
725+
// helper.buildUIAndRunTest(listView, testAction);
726+
//}

ui/list-view/list-view.android.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export class ListView extends common.ListView {
3636
private _android: android.widget.ListView;
3737
public _realizedItems = {};
3838
private _androidViewId: number;
39+
public _attachStateChangeListener: android.view.View.OnAttachStateChangeListener;
3940

4041
public _createUI() {
4142
this._android = new android.widget.ListView(this._context);
@@ -90,6 +91,28 @@ export class ListView extends common.ListView {
9091
}
9192
}
9293
}));
94+
95+
this._attachStateChangeListener = new android.view.View.OnAttachStateChangeListener({
96+
get owner() {
97+
return that.get();
98+
},
99+
100+
onViewAttachedToWindow: function (view: android.view.View) {
101+
//
102+
},
103+
onViewDetachedFromWindow: function (androidView: android.view.View) {
104+
var owner = that.get();
105+
if (!owner) {
106+
return;
107+
}
108+
109+
var view: viewModule.View = this.owner._realizedItems[androidView.hashCode()];
110+
if (!view) {
111+
return;
112+
}
113+
view.onUnloaded();
114+
}
115+
});
93116
}
94117

95118
get android(): android.widget.ListView {
@@ -213,6 +236,10 @@ class ListViewAdapter extends android.widget.BaseAdapter {
213236
}
214237
}
215238

239+
if (!this._listView._realizedItems[convertView.hashCode()]) {
240+
convertView.addOnAttachStateChangeListener(this._listView._attachStateChangeListener);
241+
}
242+
216243
this._listView._realizedItems[convertView.hashCode()] = args.view;
217244
// cache the realized index (used to raise the ItemLoading event upon scroll stop)
218245
args.view[REALIZED_INDEX] = index;
@@ -222,4 +249,5 @@ class ListViewAdapter extends android.widget.BaseAdapter {
222249

223250
return convertView;
224251
}
225-
}
252+
}
253+

ui/list-view/list-view.ios.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ class ListViewCell extends UITableViewCell {
2323
static new(): ListViewCell {
2424
return <ListViewCell>super.new();
2525
}
26+
27+
public removeFromSuperview(): void {
28+
super.removeFromSuperview();
29+
var view: view.View = (<any>this).view;
30+
if (view) {
31+
view.onUnloaded();
32+
}
33+
}
2634
}
2735

2836
function notifyForItemAtIndex(listView: definition.ListView, cell: any, eventName: string, indexPath: NSIndexPath) {

0 commit comments

Comments
 (0)