@nativescript/core 9.0.0-next-11-05-2025-19118881386 → 9.0.0-next-11-12-2025-19288121507
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/application/application-common.d.ts +29 -10
- package/application/application-common.js +58 -5
- package/application/application-common.js.map +1 -1
- package/application/application-interfaces.d.ts +10 -0
- package/application/application-shims.d.ts +27 -0
- package/application/application-shims.js +27 -0
- package/application/application-shims.js.map +1 -1
- package/application/application.android.d.ts +3 -0
- package/application/application.android.js +348 -349
- package/application/application.android.js.map +1 -1
- package/application/application.ios.d.ts +3 -0
- package/application/application.ios.js +30 -19
- package/application/application.ios.js.map +1 -1
- package/config/config.interface.d.ts +21 -0
- package/connectivity/index.android.js +22 -22
- package/connectivity/index.android.js.map +1 -1
- package/core-types/index.d.ts +10 -1
- package/core-types/index.js +10 -1
- package/core-types/index.js.map +1 -1
- package/core-types/validators.js +12 -6
- package/core-types/validators.js.map +1 -1
- package/data/observable/index.d.ts +2 -1
- package/data/observable/index.js +31 -19
- package/data/observable/index.js.map +1 -1
- package/fps-meter/fps-native.ios.js +1 -1
- package/fps-meter/fps-native.ios.js.map +1 -1
- package/http/http-request/index.ios.js +1 -1
- package/http/http-request/index.ios.js.map +1 -1
- package/image-source/index.d.ts +2 -2
- package/package.json +1 -1
- package/platform/screen/index.d.ts +5 -0
- package/platforms/android/widgets-release.aar +0 -0
- package/timer/index.ios.js +1 -1
- package/timer/index.ios.js.map +1 -1
- package/ui/action-bar/index.android.js +18 -18
- package/ui/action-bar/index.android.js.map +1 -1
- package/ui/action-bar/index.ios.js +2 -4
- package/ui/action-bar/index.ios.js.map +1 -1
- package/ui/animation/index.ios.js +2 -3
- package/ui/animation/index.ios.js.map +1 -1
- package/ui/button/index.android.js +20 -20
- package/ui/button/index.android.js.map +1 -1
- package/ui/button/index.ios.d.ts +2 -1
- package/ui/button/index.ios.js +28 -10
- package/ui/button/index.ios.js.map +1 -1
- package/ui/core/control-state-change/index.ios.js +1 -1
- package/ui/core/control-state-change/index.ios.js.map +1 -1
- package/ui/core/view/index.android.d.ts +2 -0
- package/ui/core/view/index.android.js +221 -194
- package/ui/core/view/index.android.js.map +1 -1
- package/ui/core/view/index.d.ts +26 -3
- package/ui/core/view/index.ios.d.ts +3 -2
- package/ui/core/view/index.ios.js +25 -11
- package/ui/core/view/index.ios.js.map +1 -1
- package/ui/core/view/view-common.d.ts +10 -8
- package/ui/core/view/view-common.js +7 -0
- package/ui/core/view/view-common.js.map +1 -1
- package/ui/core/view/view-helper/index.d.ts +5 -0
- package/ui/core/view/view-helper/index.ios.d.ts +5 -4
- package/ui/core/view/view-helper/index.ios.js +20 -23
- package/ui/core/view/view-helper/index.ios.js.map +1 -1
- package/ui/core/view/view-helper/view-helper-common.js +7 -0
- package/ui/core/view/view-helper/view-helper-common.js.map +1 -1
- package/ui/date-picker/index.android.js +38 -38
- package/ui/date-picker/index.android.js.map +1 -1
- package/ui/date-picker/index.ios.js +1 -1
- package/ui/date-picker/index.ios.js.map +1 -1
- package/ui/editable-text-base/index.android.js +34 -34
- package/ui/editable-text-base/index.android.js.map +1 -1
- package/ui/frame/fragment.transitions.android.d.ts +2 -1
- package/ui/frame/fragment.transitions.android.js +106 -104
- package/ui/frame/fragment.transitions.android.js.map +1 -1
- package/ui/frame/fragment.transitions.d.ts +3 -2
- package/ui/frame/index.android.js +2 -2
- package/ui/frame/index.android.js.map +1 -1
- package/ui/frame/index.ios.d.ts +2 -1
- package/ui/frame/index.ios.js +83 -43
- package/ui/frame/index.ios.js.map +1 -1
- package/ui/gestures/index.android.js +129 -130
- package/ui/gestures/index.android.js.map +1 -1
- package/ui/gestures/index.ios.js +3 -5
- package/ui/gestures/index.ios.js.map +1 -1
- package/ui/gestures/touch-manager.js +32 -32
- package/ui/gestures/touch-manager.js.map +1 -1
- package/ui/image/index.android.js +19 -19
- package/ui/image/index.android.js.map +1 -1
- package/ui/image-cache/index.android.js +12 -14
- package/ui/image-cache/index.android.js.map +1 -1
- package/ui/image-cache/index.ios.js +6 -6
- package/ui/image-cache/index.ios.js.map +1 -1
- package/ui/index.d.ts +2 -1
- package/ui/index.js +1 -0
- package/ui/index.js.map +1 -1
- package/ui/label/index.android.js +4 -1
- package/ui/label/index.android.js.map +1 -1
- package/ui/label/index.ios.d.ts +2 -1
- package/ui/label/index.ios.js +12 -2
- package/ui/label/index.ios.js.map +1 -1
- package/ui/layouts/flexbox-layout/index.ios.js +3 -6
- package/ui/layouts/flexbox-layout/index.ios.js.map +1 -1
- package/ui/layouts/stack-layout/index.ios.js +6 -0
- package/ui/layouts/stack-layout/index.ios.js.map +1 -1
- package/ui/list-picker/index.android.js +35 -35
- package/ui/list-picker/index.android.js.map +1 -1
- package/ui/list-picker/index.ios.js +2 -2
- package/ui/list-picker/index.ios.js.map +1 -1
- package/ui/list-view/index.android.d.ts +26 -1
- package/ui/list-view/index.android.js +761 -143
- package/ui/list-view/index.android.js.map +1 -1
- package/ui/list-view/index.d.ts +127 -0
- package/ui/list-view/index.ios.d.ts +34 -2
- package/ui/list-view/index.ios.js +557 -21
- package/ui/list-view/index.ios.js.map +1 -1
- package/ui/list-view/list-view-common.d.ts +22 -1
- package/ui/list-view/list-view-common.js +85 -0
- package/ui/list-view/list-view-common.js.map +1 -1
- package/ui/page/index.ios.js +25 -64
- package/ui/page/index.ios.js.map +1 -1
- package/ui/scroll-view/index.d.ts +1 -1
- package/ui/scroll-view/index.ios.d.ts +2 -0
- package/ui/scroll-view/index.ios.js +31 -12
- package/ui/scroll-view/index.ios.js.map +1 -1
- package/ui/scroll-view/scroll-view-common.d.ts +3 -8
- package/ui/scroll-view/scroll-view-common.js +4 -4
- package/ui/scroll-view/scroll-view-common.js.map +1 -1
- package/ui/search-bar/index.android.js +48 -52
- package/ui/search-bar/index.android.js.map +1 -1
- package/ui/search-bar/index.ios.js +3 -6
- package/ui/search-bar/index.ios.js.map +1 -1
- package/ui/segmented-bar/index.android.js +56 -58
- package/ui/segmented-bar/index.android.js.map +1 -1
- package/ui/segmented-bar/index.ios.js +1 -1
- package/ui/segmented-bar/index.ios.js.map +1 -1
- package/ui/slider/index.android.js +23 -25
- package/ui/slider/index.android.js.map +1 -1
- package/ui/slider/index.ios.js +2 -2
- package/ui/slider/index.ios.js.map +1 -1
- package/ui/split-view/index.android.d.ts +4 -0
- package/ui/split-view/index.android.js +4 -0
- package/ui/split-view/index.android.js.map +1 -0
- package/ui/split-view/index.d.ts +11 -0
- package/ui/split-view/index.ios.d.ts +39 -0
- package/ui/split-view/index.ios.js +368 -0
- package/ui/split-view/index.ios.js.map +1 -0
- package/ui/split-view/split-view-common.d.ts +51 -0
- package/ui/split-view/split-view-common.js +111 -0
- package/ui/split-view/split-view-common.js.map +1 -0
- package/ui/styling/style/index.d.ts +2 -0
- package/ui/styling/style/index.js.map +1 -1
- package/ui/styling/style-properties.d.ts +1 -0
- package/ui/styling/style-properties.js +7 -0
- package/ui/styling/style-properties.js.map +1 -1
- package/ui/switch/index.android.js +18 -18
- package/ui/switch/index.android.js.map +1 -1
- package/ui/switch/index.ios.d.ts +1 -0
- package/ui/switch/index.ios.js +62 -12
- package/ui/switch/index.ios.js.map +1 -1
- package/ui/tab-view/index.android.js +185 -187
- package/ui/tab-view/index.android.js.map +1 -1
- package/ui/tab-view/index.d.ts +17 -1
- package/ui/tab-view/index.ios.d.ts +13 -5
- package/ui/tab-view/index.ios.js +253 -49
- package/ui/tab-view/index.ios.js.map +1 -1
- package/ui/tab-view/tab-view-common.d.ts +14 -0
- package/ui/tab-view/tab-view-common.js +15 -0
- package/ui/tab-view/tab-view-common.js.map +1 -1
- package/ui/text-base/index.android.d.ts +2 -1
- package/ui/text-base/index.android.js +133 -101
- package/ui/text-base/index.android.js.map +1 -1
- package/ui/text-base/index.d.ts +5 -0
- package/ui/text-base/index.ios.js +12 -18
- package/ui/text-base/index.ios.js.map +1 -1
- package/ui/text-base/text-base-common.d.ts +2 -1
- package/ui/text-base/text-base-common.js +1 -0
- package/ui/text-base/text-base-common.js.map +1 -1
- package/ui/text-field/index.ios.d.ts +2 -1
- package/ui/text-field/index.ios.js +9 -5
- package/ui/text-field/index.ios.js.map +1 -1
- package/ui/text-view/index.ios.d.ts +2 -1
- package/ui/text-view/index.ios.js +12 -7
- package/ui/text-view/index.ios.js.map +1 -1
- package/ui/time-picker/index.android.js +21 -21
- package/ui/time-picker/index.android.js.map +1 -1
- package/ui/time-picker/index.ios.js +1 -1
- package/ui/time-picker/index.ios.js.map +1 -1
- package/ui/transition/fade-transition.ios.js +5 -6
- package/ui/transition/fade-transition.ios.js.map +1 -1
- package/ui/transition/modal-transition.ios.js +19 -26
- package/ui/transition/modal-transition.ios.js.map +1 -1
- package/ui/transition/page-transition.android.js +3 -12
- package/ui/transition/page-transition.android.js.map +1 -1
- package/ui/transition/page-transition.ios.js +19 -25
- package/ui/transition/page-transition.ios.js.map +1 -1
- package/ui/transition/slide-transition.ios.js +5 -6
- package/ui/transition/slide-transition.ios.js.map +1 -1
- package/ui/web-view/index.android.js +58 -62
- package/ui/web-view/index.android.js.map +1 -1
- package/ui/web-view/index.ios.js +18 -18
- package/ui/web-view/index.ios.js.map +1 -1
- package/utils/common.d.ts +3 -1
- package/utils/common.js +9 -3
- package/utils/common.js.map +1 -1
- package/utils/index.d.ts +6 -0
- package/utils/layout-helper/index.android.d.ts +1 -0
- package/utils/layout-helper/index.android.js +9 -0
- package/utils/layout-helper/index.android.js.map +1 -1
- package/utils/layout-helper/index.d.ts +5 -0
- package/utils/layout-helper/index.ios.d.ts +1 -0
- package/utils/layout-helper/index.ios.js +4 -0
- package/utils/layout-helper/index.ios.js.map +1 -1
- package/utils/native-helper.ios.js +20 -20
- package/utils/native-helper.ios.js.map +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ListViewBase, separatorColorProperty, itemTemplatesProperty } from './list-view-common';
|
|
1
|
+
import { ListViewBase, separatorColorProperty, itemTemplatesProperty, stickyHeaderProperty, stickyHeaderTemplateProperty, sectionedProperty, showSearchProperty } from './list-view-common';
|
|
2
|
+
import { View } from '../core/view';
|
|
2
3
|
import { PercentLength } from '../styling/length-shared';
|
|
3
4
|
import { unsetValue } from '../core/properties/property-shared';
|
|
4
5
|
import { Color } from '../../color';
|
|
@@ -7,39 +8,47 @@ import { StackLayout } from '../layouts/stack-layout';
|
|
|
7
8
|
import { ProxyViewContainer } from '../proxy-view-container';
|
|
8
9
|
import { LayoutBase } from '../layouts/layout-base';
|
|
9
10
|
import { profile } from '../../profiling';
|
|
11
|
+
import { Trace } from '../../trace';
|
|
12
|
+
import { Builder } from '../builder';
|
|
13
|
+
import { Label } from '../label';
|
|
10
14
|
export * from './list-view-common';
|
|
11
15
|
const ITEMLOADING = ListViewBase.itemLoadingEvent;
|
|
12
16
|
const LOADMOREITEMS = ListViewBase.loadMoreItemsEvent;
|
|
13
17
|
const ITEMTAP = ListViewBase.itemTapEvent;
|
|
18
|
+
const SEARCHCHANGE = ListViewBase.searchChangeEvent;
|
|
19
|
+
const STICKY_HEADER_Z_INDEX = 1000;
|
|
20
|
+
const SEARCH_VIEW_Z_INDEX = 2000;
|
|
21
|
+
// View type constants for sectioned lists
|
|
22
|
+
const ITEM_VIEW_TYPE = 0;
|
|
14
23
|
let ItemClickListener;
|
|
15
24
|
function initializeItemClickListener() {
|
|
16
25
|
if (ItemClickListener) {
|
|
17
26
|
return;
|
|
18
27
|
}
|
|
19
|
-
var ItemClickListenerImpl =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}(java.lang.Object));
|
|
28
|
+
var ItemClickListenerImpl = (function (_super) {
|
|
29
|
+
__extends(ItemClickListenerImpl, _super);
|
|
30
|
+
function ItemClickListenerImpl(owner) {
|
|
31
|
+
var _this = _super.call(this) || this;
|
|
32
|
+
_this.owner = owner;
|
|
33
|
+
return global.__native(_this);
|
|
34
|
+
}
|
|
35
|
+
ItemClickListenerImpl.prototype.onItemClick = function (parent, convertView, index, id) {
|
|
36
|
+
var owner = this.owner;
|
|
37
|
+
var view = owner._realizedItems.get(convertView).view;
|
|
38
|
+
owner.notify({
|
|
39
|
+
eventName: ITEMTAP,
|
|
40
|
+
object: owner,
|
|
41
|
+
index: index,
|
|
42
|
+
view: view,
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
var _a;
|
|
46
|
+
ItemClickListenerImpl = __decorate([
|
|
47
|
+
Interfaces([android.widget.AdapterView.OnItemClickListener]),
|
|
48
|
+
__metadata("design:paramtypes", [typeof (_a = typeof ListView !== "undefined" && ListView) === "function" ? _a : Object])
|
|
49
|
+
], ItemClickListenerImpl);
|
|
50
|
+
return ItemClickListenerImpl;
|
|
51
|
+
}(java.lang.Object));
|
|
43
52
|
ItemClickListener = ItemClickListenerImpl;
|
|
44
53
|
}
|
|
45
54
|
export class ListView extends ListViewBase {
|
|
@@ -49,6 +58,11 @@ export class ListView extends ListViewBase {
|
|
|
49
58
|
this._realizedItems = new Map();
|
|
50
59
|
this._availableViews = new Map();
|
|
51
60
|
this._realizedTemplates = new Map();
|
|
61
|
+
this._stickyHeaderHeight = 0;
|
|
62
|
+
this._hiddenHeaderPositions = new Set(); // Track which headers to hide
|
|
63
|
+
}
|
|
64
|
+
get hasSearchView() {
|
|
65
|
+
return !!this._searchView;
|
|
52
66
|
}
|
|
53
67
|
_ensureAvailableViews(templateKey) {
|
|
54
68
|
if (!this._availableViews.has(templateKey)) {
|
|
@@ -123,6 +137,7 @@ export class ListView extends ListViewBase {
|
|
|
123
137
|
this._androidViewId = android.view.View.generateViewId();
|
|
124
138
|
}
|
|
125
139
|
nativeView.setId(this._androidViewId);
|
|
140
|
+
// Don't setup search here - wait for onLoaded when context is properly available
|
|
126
141
|
}
|
|
127
142
|
disposeNativeView() {
|
|
128
143
|
const nativeView = this.nativeViewProtected;
|
|
@@ -133,13 +148,40 @@ export class ListView extends ListViewBase {
|
|
|
133
148
|
if (nativeView.adapter) {
|
|
134
149
|
nativeView.adapter.owner = null;
|
|
135
150
|
}
|
|
151
|
+
// Cleanup search
|
|
152
|
+
this._cleanupSearchView();
|
|
153
|
+
// Cleanup sticky header
|
|
154
|
+
this._cleanupStickyHeader();
|
|
136
155
|
this.clearRealizedCells();
|
|
137
156
|
super.disposeNativeView();
|
|
138
157
|
}
|
|
158
|
+
_cleanupStickyHeader() {
|
|
159
|
+
// Remove scroll listener
|
|
160
|
+
if (this._scrollListener) {
|
|
161
|
+
this.nativeViewProtected.setOnScrollListener(null);
|
|
162
|
+
this._scrollListener = null;
|
|
163
|
+
}
|
|
164
|
+
// Remove sticky header from parent
|
|
165
|
+
if (this._stickyHeaderView && this._stickyHeaderView.parent) {
|
|
166
|
+
this._stickyHeaderView.parent._removeView(this._stickyHeaderView);
|
|
167
|
+
}
|
|
168
|
+
this._stickyHeaderView = null;
|
|
169
|
+
this._stickyHeaderHeight = 0;
|
|
170
|
+
// Clear hidden headers
|
|
171
|
+
this._hiddenHeaderPositions.clear();
|
|
172
|
+
}
|
|
139
173
|
onLoaded() {
|
|
140
174
|
super.onLoaded();
|
|
141
175
|
// Without this call itemClick won't be fired... :(
|
|
142
176
|
this.requestLayout();
|
|
177
|
+
// Setup sticky header if enabled
|
|
178
|
+
if (this.stickyHeader && this.sectioned && this.stickyHeaderTemplate) {
|
|
179
|
+
this._setupStickyHeader();
|
|
180
|
+
}
|
|
181
|
+
// Setup search if enabled and not already set up
|
|
182
|
+
if (this.showSearch && !this._searchView && this.nativeViewProtected && this.nativeViewProtected.getAdapter()) {
|
|
183
|
+
this._setupSearchView();
|
|
184
|
+
}
|
|
143
185
|
}
|
|
144
186
|
refresh() {
|
|
145
187
|
const nativeView = this.nativeViewProtected;
|
|
@@ -152,7 +194,19 @@ export class ListView extends ListViewBase {
|
|
|
152
194
|
view.bindingContext = null;
|
|
153
195
|
}
|
|
154
196
|
});
|
|
155
|
-
|
|
197
|
+
// Safely refresh the adapter - no HeaderViewListAdapter issues since we don't use headers
|
|
198
|
+
const adapter = nativeView.getAdapter();
|
|
199
|
+
if (adapter instanceof android.widget.BaseAdapter) {
|
|
200
|
+
try {
|
|
201
|
+
adapter.notifyDataSetChanged();
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
if (Trace.isEnabled()) {
|
|
205
|
+
Trace.error('Error refreshing adapter, recreating: ' + error);
|
|
206
|
+
}
|
|
207
|
+
nativeView.setAdapter(new ListViewAdapterClass(this));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
156
210
|
}
|
|
157
211
|
scrollToIndex(index) {
|
|
158
212
|
const nativeView = this.nativeViewProtected;
|
|
@@ -213,6 +267,217 @@ export class ListView extends ListViewBase {
|
|
|
213
267
|
const end = nativeView.getLastVisiblePosition();
|
|
214
268
|
return index >= start && index <= end;
|
|
215
269
|
}
|
|
270
|
+
// Sticky header methods
|
|
271
|
+
_setupStickyHeader() {
|
|
272
|
+
if (!this.stickyHeader || !this.sectioned || !this.stickyHeaderTemplate) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
// Create the sticky header view
|
|
276
|
+
this._createStickyHeaderView();
|
|
277
|
+
// Add it as an overlay to the parent
|
|
278
|
+
this._addStickyHeaderToParent();
|
|
279
|
+
// Add padding to ListView so content doesn't hide behind sticky header
|
|
280
|
+
this._addListViewPadding();
|
|
281
|
+
// Setup scroll listener to update header content
|
|
282
|
+
this._setupScrollListener();
|
|
283
|
+
}
|
|
284
|
+
_createStickyHeaderView() {
|
|
285
|
+
if (this._stickyHeaderView) {
|
|
286
|
+
return; // Already created
|
|
287
|
+
}
|
|
288
|
+
// Create header view using the same template as section headers
|
|
289
|
+
if (typeof this.stickyHeaderTemplate === 'string') {
|
|
290
|
+
try {
|
|
291
|
+
this._stickyHeaderView = Builder.parse(this.stickyHeaderTemplate, this);
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
// Fallback to simple label
|
|
295
|
+
this._stickyHeaderView = new Label();
|
|
296
|
+
this._stickyHeaderView.text = 'Header Error';
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (!this._stickyHeaderView) {
|
|
300
|
+
// Default header
|
|
301
|
+
this._stickyHeaderView = new Label();
|
|
302
|
+
this._stickyHeaderView.text = 'Section 0';
|
|
303
|
+
}
|
|
304
|
+
// Set initial binding context (section 0)
|
|
305
|
+
this._updateStickyHeader(0);
|
|
306
|
+
}
|
|
307
|
+
_addStickyHeaderToParent() {
|
|
308
|
+
if (!this._stickyHeaderView || !this.parent) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
// Remove from current parent if it has one (likely the ListView from Builder.parse)
|
|
312
|
+
if (this._stickyHeaderView.parent) {
|
|
313
|
+
this._stickyHeaderView.parent._removeView(this._stickyHeaderView);
|
|
314
|
+
}
|
|
315
|
+
// Set proper sizing - don't stretch to fill parent
|
|
316
|
+
this._stickyHeaderView.width = { unit: '%', value: 100 };
|
|
317
|
+
this._stickyHeaderView.height = 'auto'; // Let it size to content
|
|
318
|
+
this._stickyHeaderView.verticalAlignment = 'top';
|
|
319
|
+
this._stickyHeaderView.horizontalAlignment = 'stretch';
|
|
320
|
+
// Add sticky header to the parent layout
|
|
321
|
+
// If search view exists, position sticky header after it (index 1), otherwise at top (index 0)
|
|
322
|
+
const parentLayout = this.parent;
|
|
323
|
+
const hasSearchView = this.showSearch && this._searchView && this._searchView._wrapper;
|
|
324
|
+
if (parentLayout instanceof StackLayout) {
|
|
325
|
+
const insertIndex = hasSearchView ? 1 : 0;
|
|
326
|
+
parentLayout.insertChild(this._stickyHeaderView, insertIndex);
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
parentLayout._addView(this._stickyHeaderView);
|
|
330
|
+
}
|
|
331
|
+
// When search is enabled, position sticky header below search view with proper top margin
|
|
332
|
+
if (this.showSearch && this._searchView) {
|
|
333
|
+
// Add top margin to push sticky header below search view
|
|
334
|
+
this._stickyHeaderView.marginTop = 0; // Reset any previous margin
|
|
335
|
+
// Position sticky header with proper offset using native positioning
|
|
336
|
+
if (this._stickyHeaderView.nativeViewProtected) {
|
|
337
|
+
this._stickyHeaderView.nativeViewProtected.setZ(STICKY_HEADER_Z_INDEX);
|
|
338
|
+
// Use a timeout to ensure search view is measured first
|
|
339
|
+
setTimeout(() => {
|
|
340
|
+
if (this._searchView && this._searchView._wrapper) {
|
|
341
|
+
const searchWrapper = this._searchView._wrapper;
|
|
342
|
+
if (searchWrapper.nativeViewProtected) {
|
|
343
|
+
const searchHeight = searchWrapper.nativeViewProtected.getMeasuredHeight() || 50;
|
|
344
|
+
// Position sticky header below search view using translation
|
|
345
|
+
if (this._stickyHeaderView.nativeViewProtected) {
|
|
346
|
+
this._stickyHeaderView.nativeViewProtected.setTranslationY(searchHeight);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}, 100);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
// No search view - position at top
|
|
355
|
+
if (this._stickyHeaderView.nativeViewProtected) {
|
|
356
|
+
this._stickyHeaderView.nativeViewProtected.setZ(STICKY_HEADER_Z_INDEX);
|
|
357
|
+
this._stickyHeaderView.nativeViewProtected.setTranslationY(0);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
_addListViewPadding() {
|
|
362
|
+
if (!this._stickyHeaderView) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
// Calculate total top padding: search view height + sticky header height
|
|
366
|
+
let searchViewHeight = 0;
|
|
367
|
+
if (this.showSearch && this._searchView && this._searchView._wrapper) {
|
|
368
|
+
const searchWrapper = this._searchView._wrapper;
|
|
369
|
+
if (searchWrapper.nativeViewProtected && searchWrapper.nativeViewProtected.getMeasuredHeight() > 0) {
|
|
370
|
+
searchViewHeight = searchWrapper.nativeViewProtected.getMeasuredHeight();
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
searchViewHeight = 50; // Default search view height
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// Apply immediate padding with defaults to prevent content hiding
|
|
377
|
+
const defaultHeaderHeight = 50; // Reasonable default height in dp
|
|
378
|
+
const totalPadding = searchViewHeight + defaultHeaderHeight;
|
|
379
|
+
this.nativeViewProtected.setPadding(0, totalPadding, 0, 0);
|
|
380
|
+
this._stickyHeaderHeight = defaultHeaderHeight;
|
|
381
|
+
// Request layout to ensure proper measurement
|
|
382
|
+
this._stickyHeaderView.requestLayout();
|
|
383
|
+
// Then measure and adjust padding if needed using a layout listener for determinism
|
|
384
|
+
const stickyHeaderNativeView = this._stickyHeaderView && this._stickyHeaderView.nativeViewProtected;
|
|
385
|
+
if (stickyHeaderNativeView) {
|
|
386
|
+
const layoutListener = new android.view.View.OnLayoutChangeListener({
|
|
387
|
+
onLayoutChange: (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) => {
|
|
388
|
+
if (v.getMeasuredHeight() > 0) {
|
|
389
|
+
const measuredHeaderHeight = v.getMeasuredHeight();
|
|
390
|
+
let finalSearchHeight = searchViewHeight;
|
|
391
|
+
// Re-measure search view if needed
|
|
392
|
+
if (this.showSearch && this._searchView && this._searchView._wrapper) {
|
|
393
|
+
const searchWrapper = this._searchView._wrapper;
|
|
394
|
+
if (searchWrapper.nativeViewProtected && searchWrapper.nativeViewProtected.getMeasuredHeight() > 0) {
|
|
395
|
+
finalSearchHeight = searchWrapper.nativeViewProtected.getMeasuredHeight();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
// Calculate final padding: search height + sticky header height + small buffer
|
|
399
|
+
const totalPaddingHeight = finalSearchHeight + measuredHeaderHeight + 4;
|
|
400
|
+
this._stickyHeaderHeight = measuredHeaderHeight;
|
|
401
|
+
this.nativeViewProtected.setPadding(0, totalPaddingHeight, 0, 0);
|
|
402
|
+
this.scrollToIndex(0);
|
|
403
|
+
// Remove the listener after first valid layout
|
|
404
|
+
v.removeOnLayoutChangeListener(layoutListener);
|
|
405
|
+
}
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
stickyHeaderNativeView.addOnLayoutChangeListener(layoutListener);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
_setupScrollListener() {
|
|
412
|
+
if (this._scrollListener) {
|
|
413
|
+
return; // Already setup
|
|
414
|
+
}
|
|
415
|
+
const owner = this;
|
|
416
|
+
this._scrollListener = new android.widget.AbsListView.OnScrollListener({
|
|
417
|
+
onScrollStateChanged(view, scrollState) {
|
|
418
|
+
// Not needed for sticky headers
|
|
419
|
+
},
|
|
420
|
+
onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount) {
|
|
421
|
+
if (owner.sectioned && owner._stickyHeaderView) {
|
|
422
|
+
const currentSection = owner._getCurrentSection(firstVisibleItem);
|
|
423
|
+
owner._updateStickyHeader(currentSection);
|
|
424
|
+
// Hide section headers when they would appear right below sticky header
|
|
425
|
+
owner._updateHiddenHeaders(firstVisibleItem);
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
this.nativeViewProtected.setOnScrollListener(this._scrollListener);
|
|
430
|
+
}
|
|
431
|
+
_getCurrentSection(firstVisibleItem) {
|
|
432
|
+
if (!this.sectioned) {
|
|
433
|
+
return 0;
|
|
434
|
+
}
|
|
435
|
+
// Convert the first visible list position to section number
|
|
436
|
+
let currentPosition = 0;
|
|
437
|
+
const sectionCount = this._getSectionCount();
|
|
438
|
+
for (let section = 0; section < sectionCount; section++) {
|
|
439
|
+
// Check if firstVisibleItem is in this section (header or items)
|
|
440
|
+
const sectionItems = this._getItemsInSection(section) || [];
|
|
441
|
+
const itemsInSection = sectionItems.length || 0;
|
|
442
|
+
const sectionEndPosition = currentPosition + 1 + itemsInSection; // +1 for header
|
|
443
|
+
if (firstVisibleItem < sectionEndPosition) {
|
|
444
|
+
return section;
|
|
445
|
+
}
|
|
446
|
+
currentPosition = sectionEndPosition;
|
|
447
|
+
}
|
|
448
|
+
return Math.max(0, sectionCount - 1); // Fallback to last section
|
|
449
|
+
}
|
|
450
|
+
_updateStickyHeader(section) {
|
|
451
|
+
if (!this._stickyHeaderView) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
// Update binding context to match the current section
|
|
455
|
+
const sectionData = this._getSectionData(section);
|
|
456
|
+
if (sectionData) {
|
|
457
|
+
this._stickyHeaderView.bindingContext = sectionData;
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
this._stickyHeaderView.bindingContext = { title: `Section ${section}`, section: section };
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
_updateHiddenHeaders(firstVisibleItem) {
|
|
464
|
+
const previousHiddenHeaders = new Set(this._hiddenHeaderPositions);
|
|
465
|
+
this._hiddenHeaderPositions.clear();
|
|
466
|
+
// If we're at the very top (first item is position 0, which is the first section header),
|
|
467
|
+
// hide that section header to avoid duplication with sticky header
|
|
468
|
+
if (firstVisibleItem === 0) {
|
|
469
|
+
this._hiddenHeaderPositions.add(0); // Hide the first section header position
|
|
470
|
+
}
|
|
471
|
+
// If hidden headers changed, refresh the adapter
|
|
472
|
+
const hiddenHeadersChanged = previousHiddenHeaders.size !== this._hiddenHeaderPositions.size || [...previousHiddenHeaders].some((pos) => !this._hiddenHeaderPositions.has(pos));
|
|
473
|
+
if (hiddenHeadersChanged) {
|
|
474
|
+
// Refresh adapter to update visibility
|
|
475
|
+
const adapter = this.nativeViewProtected.getAdapter();
|
|
476
|
+
if (adapter instanceof android.widget.BaseAdapter) {
|
|
477
|
+
adapter.notifyDataSetChanged();
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
216
481
|
[separatorColorProperty.getDefault]() {
|
|
217
482
|
const nativeView = this.nativeViewProtected;
|
|
218
483
|
return {
|
|
@@ -239,8 +504,199 @@ export class ListView extends ListViewBase {
|
|
|
239
504
|
if (value) {
|
|
240
505
|
this._itemTemplatesInternal = this._itemTemplatesInternal.concat(value);
|
|
241
506
|
}
|
|
242
|
-
this.nativeViewProtected
|
|
243
|
-
|
|
507
|
+
if (this.nativeViewProtected) {
|
|
508
|
+
this.nativeViewProtected.setAdapter(new ListViewAdapterClass(this));
|
|
509
|
+
this.refresh();
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
// Sticky header property handlers
|
|
513
|
+
[stickyHeaderProperty.setNative](value) {
|
|
514
|
+
// Refresh adapter to handle sectioned vs non-sectioned display
|
|
515
|
+
if (this.nativeViewProtected && this.nativeViewProtected.getAdapter()) {
|
|
516
|
+
this.nativeViewProtected.setAdapter(new ListViewAdapterClass(this));
|
|
517
|
+
}
|
|
518
|
+
// Setup or cleanup sticky header
|
|
519
|
+
if (value && this.sectioned && this.stickyHeaderTemplate && this.isLoaded) {
|
|
520
|
+
this._setupStickyHeader();
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
this._cleanupStickyHeader();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
[stickyHeaderTemplateProperty.setNative](value) {
|
|
527
|
+
// Refresh adapter when template changes
|
|
528
|
+
if (this.nativeViewProtected && this.nativeViewProtected.getAdapter()) {
|
|
529
|
+
this.nativeViewProtected.setAdapter(new ListViewAdapterClass(this));
|
|
530
|
+
}
|
|
531
|
+
// Recreate sticky header with new template
|
|
532
|
+
this._cleanupStickyHeader();
|
|
533
|
+
if (value && this.stickyHeader && this.sectioned && this.isLoaded) {
|
|
534
|
+
this._setupStickyHeader();
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
[sectionedProperty.setNative](value) {
|
|
538
|
+
// Refresh adapter to handle sectioned vs non-sectioned data
|
|
539
|
+
if (this.nativeViewProtected && this.nativeViewProtected.getAdapter()) {
|
|
540
|
+
this.nativeViewProtected.setAdapter(new ListViewAdapterClass(this));
|
|
541
|
+
}
|
|
542
|
+
// Setup or cleanup sticky header based on sectioned state
|
|
543
|
+
if (value && this.stickyHeader && this.stickyHeaderTemplate && this.isLoaded) {
|
|
544
|
+
this._setupStickyHeader();
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
this._cleanupStickyHeader();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
// Search methods
|
|
551
|
+
_setupSearchView() {
|
|
552
|
+
if (this._searchView || !this.showSearch || !this.nativeViewProtected) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
// Create SearchView using the ListView's context
|
|
556
|
+
this._searchView = new android.widget.SearchView(this.nativeViewProtected.getContext());
|
|
557
|
+
this._searchView.setQueryHint('Search...');
|
|
558
|
+
this._searchView.setIconifiedByDefault(false);
|
|
559
|
+
this._searchView.setSubmitButtonEnabled(false);
|
|
560
|
+
// Setup search listener
|
|
561
|
+
const owner = this;
|
|
562
|
+
this._searchListener = new android.widget.SearchView.OnQueryTextListener({
|
|
563
|
+
onQueryTextChange(newText) {
|
|
564
|
+
const args = {
|
|
565
|
+
eventName: SEARCHCHANGE,
|
|
566
|
+
object: owner,
|
|
567
|
+
text: newText,
|
|
568
|
+
android: owner._searchView,
|
|
569
|
+
};
|
|
570
|
+
owner.notify(args);
|
|
571
|
+
return true;
|
|
572
|
+
},
|
|
573
|
+
onQueryTextSubmit(query) {
|
|
574
|
+
const args = {
|
|
575
|
+
eventName: SEARCHCHANGE,
|
|
576
|
+
object: owner,
|
|
577
|
+
text: query,
|
|
578
|
+
android: owner._searchView,
|
|
579
|
+
};
|
|
580
|
+
owner.notify(args);
|
|
581
|
+
return true;
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
this._searchView.setOnQueryTextListener(this._searchListener);
|
|
585
|
+
// Add search view to the parent container above the ListView
|
|
586
|
+
this._addSearchToParent();
|
|
587
|
+
// Add padding to ListView if no sticky header (otherwise sticky header method handles it)
|
|
588
|
+
if (!this.stickyHeader || !this._stickyHeaderView) {
|
|
589
|
+
this._addSearchPadding();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
_addSearchPadding() {
|
|
593
|
+
if (!this._searchView) {
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
// Add basic padding for search view
|
|
597
|
+
const defaultSearchHeight = 50; // Default search view height
|
|
598
|
+
this.nativeViewProtected.setPadding(0, defaultSearchHeight, 0, 0);
|
|
599
|
+
// Measure and adjust if needed
|
|
600
|
+
setTimeout(() => {
|
|
601
|
+
if (this._searchView && this._searchView._wrapper) {
|
|
602
|
+
const searchWrapper = this._searchView._wrapper;
|
|
603
|
+
if (searchWrapper.nativeViewProtected && searchWrapper.nativeViewProtected.getMeasuredHeight() > 0) {
|
|
604
|
+
const measuredHeight = searchWrapper.nativeViewProtected.getMeasuredHeight();
|
|
605
|
+
this.nativeViewProtected.setPadding(0, measuredHeight + 4, 0, 0);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}, 100);
|
|
609
|
+
}
|
|
610
|
+
_addSearchToParent() {
|
|
611
|
+
if (!this._searchView || !this.parent) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
// Get the parent layout
|
|
615
|
+
const parentLayout = this.parent;
|
|
616
|
+
// Create a simple NativeScript wrapper for the native SearchView
|
|
617
|
+
const searchView = this._searchView;
|
|
618
|
+
const searchViewWrapper = new (class extends View {
|
|
619
|
+
createNativeView() {
|
|
620
|
+
return searchView;
|
|
621
|
+
}
|
|
622
|
+
})();
|
|
623
|
+
// Set layout properties - ensure it's at the top
|
|
624
|
+
searchViewWrapper.height = 'auto';
|
|
625
|
+
searchViewWrapper.width = { unit: '%', value: 100 };
|
|
626
|
+
searchViewWrapper.verticalAlignment = 'top';
|
|
627
|
+
searchViewWrapper.horizontalAlignment = 'stretch';
|
|
628
|
+
// Always insert at position 0 (top) regardless of ListView position
|
|
629
|
+
if (parentLayout instanceof StackLayout) {
|
|
630
|
+
parentLayout.insertChild(searchViewWrapper, 0);
|
|
631
|
+
}
|
|
632
|
+
else {
|
|
633
|
+
// For other layout types, add as first child
|
|
634
|
+
parentLayout._addView(searchViewWrapper);
|
|
635
|
+
}
|
|
636
|
+
// Ensure search view appears above everything else
|
|
637
|
+
if (searchViewWrapper.nativeViewProtected) {
|
|
638
|
+
searchViewWrapper.nativeViewProtected.setZ(SEARCH_VIEW_Z_INDEX);
|
|
639
|
+
}
|
|
640
|
+
// Store reference for cleanup
|
|
641
|
+
this._searchView._wrapper = searchViewWrapper;
|
|
642
|
+
}
|
|
643
|
+
_cleanupSearchView() {
|
|
644
|
+
if (this._searchView) {
|
|
645
|
+
// Remove search view wrapper from parent
|
|
646
|
+
const wrapper = this._searchView._wrapper;
|
|
647
|
+
if (wrapper && wrapper.parent) {
|
|
648
|
+
wrapper.parent._removeView(wrapper);
|
|
649
|
+
}
|
|
650
|
+
// Clear listener
|
|
651
|
+
if (this._searchListener) {
|
|
652
|
+
this._searchView.setOnQueryTextListener(null);
|
|
653
|
+
this._searchListener = null;
|
|
654
|
+
}
|
|
655
|
+
this._searchView = null;
|
|
656
|
+
// Reset ListView padding if no sticky header
|
|
657
|
+
if (!this.stickyHeader || !this._stickyHeaderView) {
|
|
658
|
+
this.nativeViewProtected.setPadding(0, 0, 0, 0);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
[showSearchProperty.setNative](value) {
|
|
663
|
+
if (value) {
|
|
664
|
+
if (this.isLoaded && this.nativeViewProtected && this.nativeViewProtected.getAdapter()) {
|
|
665
|
+
this._setupSearchView();
|
|
666
|
+
// Reposition sticky header if it exists
|
|
667
|
+
if (this._stickyHeaderView) {
|
|
668
|
+
this._repositionStickyHeader();
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
this._cleanupSearchView();
|
|
674
|
+
// Reposition sticky header if it exists
|
|
675
|
+
if (this._stickyHeaderView) {
|
|
676
|
+
this._repositionStickyHeader();
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
_repositionStickyHeader() {
|
|
681
|
+
if (!this._stickyHeaderView || !this._stickyHeaderView.nativeViewProtected) {
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
// Reset positioning
|
|
685
|
+
this._stickyHeaderView.nativeViewProtected.setTranslationY(0);
|
|
686
|
+
// If search is enabled, position below search view
|
|
687
|
+
if (this.showSearch && this._searchView && this._searchView._wrapper) {
|
|
688
|
+
setTimeout(() => {
|
|
689
|
+
const searchWrapper = this._searchView._wrapper;
|
|
690
|
+
if (searchWrapper.nativeViewProtected) {
|
|
691
|
+
const searchHeight = searchWrapper.nativeViewProtected.getMeasuredHeight() || 50;
|
|
692
|
+
this._stickyHeaderView.nativeViewProtected.setTranslationY(searchHeight);
|
|
693
|
+
}
|
|
694
|
+
}, 100);
|
|
695
|
+
}
|
|
696
|
+
// Update ListView padding
|
|
697
|
+
if (this.stickyHeader && this._stickyHeaderView) {
|
|
698
|
+
this._addListViewPadding();
|
|
699
|
+
}
|
|
244
700
|
}
|
|
245
701
|
}
|
|
246
702
|
__decorate([
|
|
@@ -254,133 +710,295 @@ function ensureListViewAdapterClass() {
|
|
|
254
710
|
if (ListViewAdapterClass) {
|
|
255
711
|
return;
|
|
256
712
|
}
|
|
257
|
-
var ListViewAdapter =
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
ListViewAdapter.prototype.getCount = function () {
|
|
265
|
-
return this.owner && this.owner.items && this.owner.items.length ? this.owner.items.length : 0;
|
|
266
|
-
};
|
|
267
|
-
ListViewAdapter.prototype.getItem = function (i) {
|
|
268
|
-
if (this.owner && this.owner.items && i < this.owner.items.length) {
|
|
269
|
-
var getItem = this.owner.items.getItem;
|
|
270
|
-
return getItem ? getItem.call(this.owner.items, i) : this.owner.items[i];
|
|
713
|
+
var ListViewAdapter = (function (_super) {
|
|
714
|
+
__extends(ListViewAdapter, _super);
|
|
715
|
+
function ListViewAdapter(owner) {
|
|
716
|
+
var _this = _super.call(this) || this;
|
|
717
|
+
_this.owner = owner;
|
|
718
|
+
return global.__native(_this);
|
|
271
719
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
720
|
+
ListViewAdapter.prototype.getCount = function () {
|
|
721
|
+
if (!this.owner) {
|
|
722
|
+
return 0;
|
|
723
|
+
}
|
|
724
|
+
var count = 0;
|
|
725
|
+
if (this.owner.sectioned) {
|
|
726
|
+
var sectionCount = this.owner._getSectionCount();
|
|
727
|
+
if (!this.owner.items || sectionCount <= 0) {
|
|
728
|
+
return 0;
|
|
729
|
+
}
|
|
730
|
+
for (var i = 0; i < sectionCount; i++) {
|
|
731
|
+
var itemsInSection = this.owner._getItemsInSection(i) || [];
|
|
732
|
+
if (itemsInSection.length > 0) {
|
|
733
|
+
count += 1;
|
|
734
|
+
count += itemsInSection.length;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
var src = this.owner.items;
|
|
740
|
+
count = src && typeof src.length === "number" ? src.length : 0;
|
|
741
|
+
}
|
|
742
|
+
return Math.max(0, count);
|
|
743
|
+
};
|
|
744
|
+
ListViewAdapter.prototype.getItem = function (i) {
|
|
745
|
+
if (!this.owner || !this.owner.items) {
|
|
746
|
+
return null;
|
|
747
|
+
}
|
|
748
|
+
var totalCount = this.getCount();
|
|
749
|
+
if (i < 0 || i >= totalCount) {
|
|
750
|
+
return null;
|
|
751
|
+
}
|
|
752
|
+
if (this.owner.sectioned) {
|
|
753
|
+
var positionInfo = this._getPositionInfo(i);
|
|
754
|
+
if (positionInfo.isHeader) {
|
|
755
|
+
return this.owner._getSectionData(positionInfo.section);
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
return this.owner._getDataItemInSection(positionInfo.section, positionInfo.itemIndex);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
else {
|
|
762
|
+
var src = this.owner.items;
|
|
763
|
+
if (src && typeof src.length === "number" && i < src.length) {
|
|
764
|
+
var getItem = src.getItem;
|
|
765
|
+
return getItem ? getItem.call(src, i) : src[i];
|
|
766
|
+
}
|
|
767
|
+
}
|
|
296
768
|
return null;
|
|
297
|
-
}
|
|
298
|
-
var totalItemCount = this.owner.items ? this.owner.items.length : 0;
|
|
299
|
-
if (index === totalItemCount - 1) {
|
|
300
|
-
this.owner.notify({
|
|
301
|
-
eventName: LOADMOREITEMS,
|
|
302
|
-
object: this.owner,
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
|
-
// Recycle an existing view or create a new one if needed.
|
|
306
|
-
var template = this.owner._getItemTemplate(index);
|
|
307
|
-
var view;
|
|
308
|
-
// convertView is of the wrong type
|
|
309
|
-
if (convertView && this.owner._getKeyFromView(convertView) !== template.key) {
|
|
310
|
-
this.owner._markViewUnused(convertView); // release this view
|
|
311
|
-
convertView = this.owner._getAvailableView(template.key); // get a view from the right type or null
|
|
312
|
-
}
|
|
313
|
-
if (convertView) {
|
|
314
|
-
view = this.owner._realizedItems.get(convertView).view;
|
|
315
|
-
}
|
|
316
|
-
if (!view) {
|
|
317
|
-
view = template.createView();
|
|
318
|
-
}
|
|
319
|
-
var args = {
|
|
320
|
-
eventName: ITEMLOADING,
|
|
321
|
-
object: this.owner,
|
|
322
|
-
index: index,
|
|
323
|
-
view: view,
|
|
324
|
-
android: parent,
|
|
325
|
-
ios: undefined,
|
|
326
769
|
};
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
770
|
+
ListViewAdapter.prototype._getPositionInfo = function (position) {
|
|
771
|
+
if (!this.owner.sectioned) {
|
|
772
|
+
return { isHeader: false, section: 0, itemIndex: position };
|
|
773
|
+
}
|
|
774
|
+
var currentPosition = 0;
|
|
775
|
+
var sectionCount = this.owner._getSectionCount();
|
|
776
|
+
for (var section = 0; section < sectionCount; section++) {
|
|
777
|
+
var itemsInSection = this.owner._getItemsInSection(section) || [];
|
|
778
|
+
if (itemsInSection.length === 0) {
|
|
779
|
+
continue;
|
|
780
|
+
}
|
|
781
|
+
if (currentPosition === position) {
|
|
782
|
+
return { isHeader: true, section: section, itemIndex: -1 };
|
|
783
|
+
}
|
|
784
|
+
currentPosition++;
|
|
785
|
+
if (position < currentPosition + itemsInSection.length) {
|
|
786
|
+
var itemIndex = position - currentPosition;
|
|
787
|
+
return { isHeader: false, section: section, itemIndex: itemIndex };
|
|
788
|
+
}
|
|
789
|
+
currentPosition += itemsInSection.length;
|
|
790
|
+
}
|
|
791
|
+
return { isHeader: false, section: 0, itemIndex: 0 };
|
|
792
|
+
};
|
|
793
|
+
ListViewAdapter.prototype.getItemId = function (i) {
|
|
794
|
+
var item = this.getItem(i);
|
|
795
|
+
var id = i;
|
|
796
|
+
if (this.owner && item && this.owner.items) {
|
|
797
|
+
id = this.owner.itemIdGenerator(item, i, this.owner.items);
|
|
798
|
+
}
|
|
799
|
+
return long(id);
|
|
800
|
+
};
|
|
801
|
+
ListViewAdapter.prototype.hasStableIds = function () {
|
|
802
|
+
return true;
|
|
803
|
+
};
|
|
804
|
+
ListViewAdapter.prototype.isEnabled = function (position) {
|
|
805
|
+
var totalCount = this.getCount();
|
|
806
|
+
if (totalCount === 0 || position < 0 || position >= totalCount) {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
if (this.owner.sectioned) {
|
|
810
|
+
var positionInfo = this._getPositionInfo(position);
|
|
811
|
+
return !positionInfo.isHeader;
|
|
812
|
+
}
|
|
813
|
+
return true;
|
|
814
|
+
};
|
|
815
|
+
ListViewAdapter.prototype.getViewTypeCount = function () {
|
|
816
|
+
var count = this.owner._itemTemplatesInternal.length;
|
|
817
|
+
if (this.owner.sectioned && this.owner.stickyHeaderTemplate) {
|
|
818
|
+
count += 1;
|
|
819
|
+
}
|
|
820
|
+
return count;
|
|
821
|
+
};
|
|
822
|
+
ListViewAdapter.prototype.getItemViewType = function (index) {
|
|
823
|
+
if (this.owner.sectioned) {
|
|
824
|
+
var positionInfo = this._getPositionInfo(index);
|
|
825
|
+
if (positionInfo.isHeader) {
|
|
826
|
+
return this.owner._itemTemplatesInternal.length;
|
|
827
|
+
}
|
|
828
|
+
else {
|
|
829
|
+
var template = this.owner._getItemTemplate(positionInfo.itemIndex);
|
|
830
|
+
return this.owner._itemTemplatesInternal.indexOf(template);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
else {
|
|
834
|
+
var template = this.owner._getItemTemplate(index);
|
|
835
|
+
return this.owner._itemTemplatesInternal.indexOf(template);
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
ListViewAdapter.prototype.getView = function (index, convertView, parent) {
|
|
839
|
+
if (!this.owner) {
|
|
840
|
+
return null;
|
|
841
|
+
}
|
|
842
|
+
var totalCount = this.getCount();
|
|
843
|
+
if (index < 0 || index >= totalCount) {
|
|
844
|
+
var emptyView = new android.view.View(this.owner._context);
|
|
845
|
+
var layoutParams = new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, 0);
|
|
846
|
+
emptyView.setLayoutParams(layoutParams);
|
|
847
|
+
return emptyView;
|
|
848
|
+
}
|
|
849
|
+
if (index === totalCount - 1) {
|
|
850
|
+
this.owner.notify({
|
|
851
|
+
eventName: LOADMOREITEMS,
|
|
852
|
+
object: this.owner,
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
if (this.owner.sectioned) {
|
|
856
|
+
var positionInfo = this._getPositionInfo(index);
|
|
857
|
+
if (positionInfo.isHeader) {
|
|
858
|
+
return this._createHeaderView(positionInfo.section, convertView, parent, index);
|
|
859
|
+
}
|
|
860
|
+
else {
|
|
861
|
+
return this._createItemView(positionInfo.section, positionInfo.itemIndex, convertView, parent);
|
|
862
|
+
}
|
|
334
863
|
}
|
|
335
864
|
else {
|
|
336
|
-
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
865
|
+
return this._createItemView(0, index, convertView, parent);
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
ListViewAdapter.prototype._createHeaderView = function (section, convertView, parent, index) {
|
|
869
|
+
if (this.owner._hiddenHeaderPositions.has(index)) {
|
|
870
|
+
var emptyView = new android.view.View(this.owner._context);
|
|
871
|
+
var layoutParams = new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, 0);
|
|
872
|
+
emptyView.setLayoutParams(layoutParams);
|
|
873
|
+
return emptyView;
|
|
874
|
+
}
|
|
875
|
+
var headerView = null;
|
|
876
|
+
var headerViewType = this.owner._itemTemplatesInternal.length;
|
|
877
|
+
if (convertView) {
|
|
878
|
+
var existingData = this.owner._realizedItems.get(convertView);
|
|
879
|
+
if (existingData && existingData.templateKey === "header_".concat(headerViewType)) {
|
|
880
|
+
headerView = existingData.view;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (!headerView) {
|
|
884
|
+
if (this.owner.stickyHeaderTemplate) {
|
|
885
|
+
if (typeof this.owner.stickyHeaderTemplate === "string") {
|
|
886
|
+
try {
|
|
887
|
+
headerView = Builder.parse(this.owner.stickyHeaderTemplate, this.owner);
|
|
888
|
+
}
|
|
889
|
+
catch (error) {
|
|
890
|
+
headerView = new Label();
|
|
891
|
+
headerView.text = "Header Error";
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
if (!headerView) {
|
|
896
|
+
headerView = new Label();
|
|
897
|
+
headerView.text = "Section ".concat(section);
|
|
898
|
+
}
|
|
899
|
+
if (!headerView.parent) {
|
|
900
|
+
if (headerView instanceof LayoutBase && !(headerView instanceof ProxyViewContainer)) {
|
|
901
|
+
this.owner._addView(headerView);
|
|
902
|
+
convertView = headerView.nativeViewProtected;
|
|
357
903
|
}
|
|
358
904
|
else {
|
|
359
|
-
|
|
360
|
-
|
|
905
|
+
var sp = new StackLayout();
|
|
906
|
+
sp.addChild(headerView);
|
|
907
|
+
this.owner._addView(sp);
|
|
908
|
+
convertView = sp.nativeViewProtected;
|
|
361
909
|
}
|
|
362
910
|
}
|
|
911
|
+
this.owner._realizedItems.set(convertView, {
|
|
912
|
+
view: headerView,
|
|
913
|
+
templateKey: "header_".concat(headerViewType),
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
var sectionData = this.owner._getSectionData(section);
|
|
917
|
+
if (sectionData) {
|
|
918
|
+
headerView.bindingContext = sectionData;
|
|
919
|
+
}
|
|
920
|
+
else {
|
|
921
|
+
headerView.bindingContext = { title: "Section ".concat(section), section: section };
|
|
922
|
+
}
|
|
923
|
+
return convertView;
|
|
924
|
+
};
|
|
925
|
+
ListViewAdapter.prototype._createItemView = function (section, itemIndex, convertView, parent) {
|
|
926
|
+
var template = this.owner._getItemTemplate(itemIndex);
|
|
927
|
+
var view;
|
|
928
|
+
if (convertView && this.owner._getKeyFromView(convertView) !== template.key) {
|
|
929
|
+
this.owner._markViewUnused(convertView);
|
|
930
|
+
convertView = this.owner._getAvailableView(template.key);
|
|
931
|
+
}
|
|
932
|
+
if (convertView) {
|
|
933
|
+
view = this.owner._realizedItems.get(convertView).view;
|
|
934
|
+
}
|
|
935
|
+
if (!view) {
|
|
936
|
+
view = template.createView();
|
|
937
|
+
}
|
|
938
|
+
var args = {
|
|
939
|
+
eventName: ITEMLOADING,
|
|
940
|
+
object: this.owner,
|
|
941
|
+
index: itemIndex,
|
|
942
|
+
view: view,
|
|
943
|
+
android: parent,
|
|
944
|
+
ios: undefined,
|
|
945
|
+
};
|
|
946
|
+
this.owner.notify(args);
|
|
947
|
+
if (!args.view) {
|
|
948
|
+
args.view = this.owner._getDefaultItemContent(itemIndex);
|
|
949
|
+
}
|
|
950
|
+
if (args.view) {
|
|
951
|
+
if (this.owner._effectiveRowHeight > -1) {
|
|
952
|
+
args.view.height = this.owner.rowHeight;
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
args.view.height = unsetValue;
|
|
956
|
+
}
|
|
957
|
+
if (this.owner.sectioned) {
|
|
958
|
+
this.owner._prepareItemInSection(args.view, section, itemIndex);
|
|
959
|
+
}
|
|
363
960
|
else {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
961
|
+
this.owner._prepareItem(args.view, itemIndex);
|
|
962
|
+
}
|
|
963
|
+
if (!args.view.parent) {
|
|
964
|
+
if (args.view instanceof LayoutBase && !(args.view instanceof ProxyViewContainer)) {
|
|
965
|
+
var mt = PercentLength.toDevicePixels(args.view.marginTop, 0, Number.NaN);
|
|
966
|
+
var mb = PercentLength.toDevicePixels(args.view.marginBottom, 0, Number.NaN);
|
|
967
|
+
var ml = PercentLength.toDevicePixels(args.view.marginLeft, 0, Number.NaN);
|
|
968
|
+
var mr = PercentLength.toDevicePixels(args.view.marginRight, 0, Number.NaN);
|
|
969
|
+
var hasMargins = mt > 0 || mb > 0 || ml > 0 || mr > 0;
|
|
970
|
+
if (hasMargins) {
|
|
971
|
+
var outer = new StackLayout();
|
|
972
|
+
outer.addChild(args.view);
|
|
973
|
+
this.owner._addView(outer);
|
|
974
|
+
convertView = outer.nativeViewProtected;
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
this.owner._addView(args.view);
|
|
978
|
+
convertView = args.view.nativeViewProtected;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
else {
|
|
982
|
+
var sp = new StackLayout();
|
|
983
|
+
sp.addChild(args.view);
|
|
984
|
+
this.owner._addView(sp);
|
|
985
|
+
convertView = sp.nativeViewProtected;
|
|
986
|
+
}
|
|
368
987
|
}
|
|
988
|
+
this.owner._registerViewToTemplate(template.key, convertView, args.view);
|
|
989
|
+
this.owner._markViewUsed(convertView);
|
|
369
990
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
], ListViewAdapter.prototype, "getView", null);
|
|
382
|
-
return ListViewAdapter;
|
|
383
|
-
}(android.widget.BaseAdapter));
|
|
991
|
+
return convertView;
|
|
992
|
+
};
|
|
993
|
+
var _a, _b, _c, _d, _e, _f;
|
|
994
|
+
__decorate([
|
|
995
|
+
profile,
|
|
996
|
+
__metadata("design:type", Function),
|
|
997
|
+
__metadata("design:paramtypes", [Number, typeof (_b = typeof android !== "undefined" && (_a = android.view) !== void 0 && _a.View) === "function" ? _b : Object, typeof (_d = typeof android !== "undefined" && (_c = android.view) !== void 0 && _c.ViewGroup) === "function" ? _d : Object]),
|
|
998
|
+
__metadata("design:returntype", typeof (_f = typeof android !== "undefined" && (_e = android.view) !== void 0 && _e.View) === "function" ? _f : Object)
|
|
999
|
+
], ListViewAdapter.prototype, "getView", null);
|
|
1000
|
+
return ListViewAdapter;
|
|
1001
|
+
}(android.widget.BaseAdapter));
|
|
384
1002
|
ListViewAdapterClass = ListViewAdapter;
|
|
385
1003
|
}
|
|
386
1004
|
//# sourceMappingURL=index.android.js.map
|