@nstudio/ui-collectionview 5.1.9-alpha.5 → 5.1.9

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/index.android.js CHANGED
@@ -1,9 +1,10 @@
1
+ var _a, _b;
1
2
  /* eslint-disable no-redeclare */
2
- import { ChangeType, ContentView, Property, ProxyViewContainer, Trace, Utils, View, booleanConverter, paddingBottomProperty, paddingLeftProperty, paddingRightProperty, paddingTopProperty, profile } from '@nativescript/core';
3
- import { CLog, CLogTypes, CollectionViewBase, ViewTemplateType, isScrollEnabledProperty, orientationProperty, reorderLongPressEnabledProperty, reorderingEnabledProperty, reverseLayoutProperty, scrollBarIndicatorVisibleProperty } from './common';
3
+ import { ChangeType, ContentView, CoreTypes, Length, Property, ProxyViewContainer, Trace, Utils, View, booleanConverter, paddingBottomProperty, paddingLeftProperty, paddingRightProperty, paddingTopProperty, profile } from '@nativescript/core';
4
+ import { itemOverlapProperty, reorderLongPressEnabledProperty, reorderingEnabledProperty, reverseLayoutProperty, scrollBarIndicatorVisibleProperty } from '.';
5
+ import { CLog, CLogTypes, CollectionViewBase, ListViewViewTypes, isScrollEnabledProperty, orientationProperty } from './common';
6
+ import { createArrayBuffer } from '@nativescript-community/arraybuffers';
4
7
  export * from './common';
5
- let CollectionViewCellHolder;
6
- let CollectionViewRecyclerView;
7
8
  var SimpleCallback = /** @class */ (function (_super) {
8
9
  __extends(SimpleCallback, _super);
9
10
  function SimpleCallback(param1, param2) {
@@ -13,13 +14,17 @@ var SimpleCallback = /** @class */ (function (_super) {
13
14
  return global.__native(_this);
14
15
  }
15
16
  SimpleCallback.prototype.onMove = function (recyclerview, viewHolder, target) {
17
+ var _a;
16
18
  var startPosition = viewHolder.getAdapterPosition();
17
19
  var endPosition = target.getAdapterPosition();
20
+ var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.get();
21
+ if (owner && !owner._canReorderToPosition(startPosition, endPosition, owner.getItemAtIndex(endPosition))) {
22
+ return false;
23
+ }
18
24
  if (this.startPosition === -1) {
19
25
  this.startPosition = startPosition;
20
26
  }
21
27
  this.endPosition = endPosition;
22
- var owner = this.owner && this.owner.get();
23
28
  if (owner) {
24
29
  owner._reorderItemInSource(startPosition, endPosition);
25
30
  return true;
@@ -27,6 +32,7 @@ var SimpleCallback = /** @class */ (function (_super) {
27
32
  return false;
28
33
  };
29
34
  SimpleCallback.prototype.onSelectedChanged = function (viewHolder, state) {
35
+ var _a;
30
36
  if (viewHolder) {
31
37
  if (this.startPosition === -1) {
32
38
  this.startPosition = viewHolder.getAdapterPosition();
@@ -34,7 +40,7 @@ var SimpleCallback = /** @class */ (function (_super) {
34
40
  }
35
41
  if (!viewHolder) {
36
42
  // this is where we identify the end of the drag and call the end event
37
- var owner = this.owner && this.owner.get();
43
+ var owner = (_a = this.owner) === null || _a === void 0 ? void 0 : _a.get();
38
44
  if (this.endPosition === -1) {
39
45
  this.endPosition = this.startPosition;
40
46
  }
@@ -66,7 +72,8 @@ var LongPressGestureListenerImpl = /** @class */ (function (_super) {
66
72
  return global.__native(_this);
67
73
  }
68
74
  LongPressGestureListenerImpl.prototype.onLongPress = function (motionEvent) {
69
- var owner = this._owner && this._owner.get();
75
+ var _a;
76
+ var owner = (_a = this._owner) === null || _a === void 0 ? void 0 : _a.get();
70
77
  if (owner) {
71
78
  owner.onReorderLongPress(motionEvent);
72
79
  }
@@ -85,6 +92,11 @@ const nestedScrollingEnabledProperty = new Property({
85
92
  defaultValue: true,
86
93
  valueConverter: booleanConverter
87
94
  });
95
+ export var SnapPosition;
96
+ (function (SnapPosition) {
97
+ SnapPosition[SnapPosition["START"] = 0] = "START";
98
+ SnapPosition[SnapPosition["END"] = 1] = "END";
99
+ })(SnapPosition || (SnapPosition = {}));
88
100
  export class CollectionView extends CollectionViewBase {
89
101
  constructor() {
90
102
  super(...arguments);
@@ -99,10 +111,30 @@ export class CollectionView extends CollectionViewBase {
99
111
  this.scrolling = false;
100
112
  this.needsScrollStartEvent = false;
101
113
  this.animateItemUpdate = false;
114
+ this.mInPropertiesSet = false;
115
+ this.mShouldUpdateInnerSize = false;
116
+ this.mShouldUpdateSpanCount = false;
117
+ this.mShouldRefresh = false;
102
118
  this.defaultPoolSize = 10;
103
119
  this.desiredPoolSize = new Map();
104
120
  this.isDragging = false;
105
121
  this._layedOut = false;
122
+ this.bindedViewHolders = new Set();
123
+ }
124
+ onResumeNativeUpdates() {
125
+ // {N} suspends properties update on `_suspendNativeUpdates`. So we only need to do this in onResumeNativeUpdates
126
+ this.mInPropertiesSet = true;
127
+ super.onResumeNativeUpdates();
128
+ this.mInPropertiesSet = false;
129
+ if (this.mShouldUpdateInnerSize) {
130
+ this.updateInnerSize();
131
+ }
132
+ if (this.mShouldUpdateSpanCount) {
133
+ this.updateSpanCount();
134
+ }
135
+ if (this.mShouldRefresh) {
136
+ this.refresh();
137
+ }
106
138
  }
107
139
  createNativeView() {
108
140
  // storing the class in a property for reuse in the future cause a materializing which is pretty slow!
@@ -122,55 +154,59 @@ export class CollectionView extends CollectionViewBase {
122
154
  return recyclerView;
123
155
  }
124
156
  initNativeView() {
125
- this.setOnLayoutChangeListener();
126
157
  super.initNativeView();
127
158
  const nativeView = this.nativeViewProtected;
128
- this.recycledViewPool = new com.nativescript.collectionview.RecycledViewPool();
129
- this.recycledViewPoolDisposeListener = new com.nativescript.collectionview.RecycledViewPool.ViewPoolListener({
130
- onViewHolderDisposed: (holder) => {
131
- if (Trace.isEnabled()) {
132
- CLog(CLogTypes.log, 'onViewHolderDisposed', holder);
133
- }
134
- if (this._viewHolders) {
135
- this._viewHolders.delete(holder);
136
- }
137
- const isNonSync = holder['defaultItemView'] === true;
138
- const view = isNonSync ? holder.view.content : holder.view;
139
- this.notifyForItemAtIndex(CollectionViewBase.itemDisposingEvent, view, holder.getAdapterPosition(), view.bindingContext, holder);
140
- if (view && view.isLoaded) {
141
- view.callUnloaded();
159
+ if (!this.recycledViewPool) {
160
+ this.recycledViewPool = new com.nativescript.collectionview.RecycledViewPool();
161
+ this.recycledViewPoolDisposeListener = new com.nativescript.collectionview.RecycledViewPool.ViewPoolListener({
162
+ onViewHolderDisposed: (holder) => {
163
+ if (Trace.isEnabled()) {
164
+ CLog(CLogTypes.log, 'onViewHolderDisposed', holder);
165
+ }
166
+ if (this._viewHolders) {
167
+ this._viewHolders.delete(holder);
168
+ }
169
+ const isNonSync = holder['defaultItemView'] === true;
170
+ const view = isNonSync ? holder.view.content : holder.view;
171
+ this.notifyForItemAtIndex(CollectionViewBase.itemDisposingEvent, view, holder.getAdapterPosition(), view.bindingContext, holder);
172
+ if (view && view.isLoaded) {
173
+ view.callUnloaded();
174
+ }
175
+ view._isAddedToNativeVisualTree = false;
176
+ //@ts-ignore
177
+ view.parent = null;
178
+ view._tearDownUI();
142
179
  }
143
- view._isAddedToNativeVisualTree = false;
144
- //@ts-ignore
145
- view.parent = null;
146
- view._tearDownUI();
147
- }
148
- });
149
- this.recycledViewPool.mListener = this.recycledViewPoolDisposeListener;
150
- const recyclerListener = (this.recyclerListener = new androidx.recyclerview.widget.RecyclerView.RecyclerListener({
151
- onViewRecycled: (holder) => {
152
- if (Trace.isEnabled()) {
153
- CLog(CLogTypes.log, 'onViewRecycled', holder);
180
+ });
181
+ this.recycledViewPool.mListener = this.recycledViewPoolDisposeListener;
182
+ }
183
+ if (Trace.isEnabled() || this.hasListeners(CollectionViewBase.itemRecyclingEvent)) {
184
+ const recyclerListener = (this.recyclerListener = new androidx.recyclerview.widget.RecyclerView.RecyclerListener({
185
+ onViewRecycled: (holder) => {
186
+ if (Trace.isEnabled()) {
187
+ CLog(CLogTypes.log, 'onViewRecycled', this, nativeView, holder);
188
+ }
189
+ const isNonSync = holder['defaultItemView'] === true;
190
+ const view = isNonSync ? holder.view.content : holder.view;
191
+ this.notifyForItemAtIndex(CollectionViewBase.itemRecyclingEvent, view, holder.getAdapterPosition(), view.bindingContext, holder);
154
192
  }
155
- const isNonSync = holder['defaultItemView'] === true;
156
- const view = isNonSync ? holder.view.content : holder.view;
157
- this.notifyForItemAtIndex(CollectionViewBase.itemRecyclingEvent, view, holder.getAdapterPosition(), view.bindingContext, holder);
158
- }
159
- }));
160
- nativeView.setRecyclerListener(recyclerListener);
193
+ }));
194
+ nativeView.setRecyclerListener(recyclerListener);
195
+ }
161
196
  nativeView.setRecycledViewPool(this.recycledViewPool);
162
- // nativeView.owner = new WeakRef(this);
163
- // nativeView.sizeChangedListener = new com.nativescript.collectionview.SizeChangedListener({
164
- // onSizeChanged: (w, h, oldW, oldH) => this.onSizeChanged(w, h),
165
- // });
166
- // const orientation = this._getLayoutManagarOrientation();
167
- // initGridLayoutManager();
168
197
  let layoutManager;
169
198
  if (CollectionViewBase.layoutStyles[this.layoutStyle]) {
170
199
  layoutManager = CollectionViewBase.layoutStyles[this.layoutStyle].createLayout(this);
171
200
  }
172
201
  else {
173
202
  layoutManager = new com.nativescript.collectionview.PreCachingGridLayoutManager(this._context, 1);
203
+ if (this.hasListeners(CollectionView.layoutCompletedEvent)) {
204
+ layoutManager.layoutCompletedListener = new com.nativescript.collectionview.GridLayoutManager.LayoutCompletedListener({
205
+ onLayoutCompleted: () => {
206
+ this.notify({ eventName: CollectionView.layoutCompletedEvent });
207
+ }
208
+ });
209
+ }
174
210
  // layoutManager = new PreCachingGridLayoutManager(this._context, 1);
175
211
  // (layoutManager as any).owner = new WeakRef(this);
176
212
  }
@@ -178,19 +214,21 @@ export class CollectionView extends CollectionViewBase {
178
214
  nativeView.setLayoutManager(layoutManager);
179
215
  nativeView.layoutManager = layoutManager;
180
216
  nativeView.sizeChangedListener = new com.nativescript.collectionview.SizeChangedListener({
181
- onSizeChanged() { },
182
- onMeasure: () => this.updateInnerSize()
217
+ onLayout: (changed, left, top, right, bottom) => changed && this.onLayout(left, top, right, bottom),
218
+ onMeasure: (widthMeasureSpec, heightMeasureSpec) => this.onMeasure(widthMeasureSpec, heightMeasureSpec)
183
219
  });
184
220
  this.spanSize = this._getSpanSize;
185
- const animator = new com.h6ah4i.android.widget.advrecyclerview.animator.RefactoredDefaultItemAnimator();
221
+ // const animator = new jp.wasabeef.recyclerview.animators.FadeInAnimator();
222
+ // // animator.setInterpolator(new android.view.animation.OvershootInterpolator());
223
+ // animator.setMoveDuration(200);
186
224
  // Change animations are enabled by default since support-v7-recyclerview v22.
187
225
  // Need to disable them when using animation indicator.
188
- animator.setSupportsChangeAnimations(false);
189
- nativeView.setItemAnimator(animator);
190
- this.refresh();
226
+ // animator.setSupportsChangeAnimations(false);
227
+ // nativeView.setItemAnimator(animator);
228
+ // enforce the first refresh for the collectionview to be ready as soon as possible
229
+ this.refresh(true);
191
230
  }
192
231
  disposeNativeView() {
193
- // clear the cache
194
232
  // this.eachChildView((view) => {
195
233
  // view.parent._removeView(view);
196
234
  // return true;
@@ -201,27 +239,24 @@ export class CollectionView extends CollectionViewBase {
201
239
  nativeView.setRecycledViewPool(null);
202
240
  this.recycledViewPoolDisposeListener = null;
203
241
  this.recycledViewPool = null;
204
- if (nativeView.scrollListener) {
205
- this.nativeView.removeOnScrollListener(nativeView.scrollListener);
206
- nativeView.scrollListener = null;
207
- this._nScrollListener = null;
208
- }
242
+ this.detachScrollListenerIfNecessary(true);
209
243
  nativeView.sizeChangedListener = null;
210
244
  nativeView.layoutManager = null;
211
245
  this._listViewAdapter = null;
212
246
  this._itemTouchHelper = null;
213
247
  this._simpleItemTouchCallback = null;
214
248
  this.disposeViewHolderViews();
215
- this._hlayoutParams = null;
216
- this._vlayoutParams = null;
217
249
  this.clearTemplateTypes();
218
250
  super.disposeNativeView();
219
251
  }
220
252
  onLoaded() {
221
253
  super.onLoaded();
222
- this.attachScrollListener();
223
- this.refresh();
254
+ this.attachScrollListenerIfNecessary();
224
255
  }
256
+ // onUnloaded() {
257
+ // super.onUnloaded();
258
+ // this.detachScrollListenerIfNecessary();
259
+ // }
225
260
  getViewForItemAtIndex(index) {
226
261
  return this.enumerateViewHolders((v) => (v.getAdapterPosition() === index ? v.view : undefined));
227
262
  }
@@ -249,28 +284,56 @@ export class CollectionView extends CollectionViewBase {
249
284
  get spanSize() {
250
285
  return this._getSpanSize;
251
286
  }
252
- attachScrollListener() {
253
- if (this._scrollOrLoadMoreChangeCount > 0 && this.isLoaded) {
254
- const nativeView = this.nativeViewProtected;
255
- if (!nativeView.scrollListener) {
256
- this._nScrollListener = new com.nativescript.collectionview.OnScrollListener.Listener({
257
- onScrollStateChanged: this.onScrollStateChanged.bind(this),
258
- onScrolled: this.onScrolled.bind(this)
287
+ nativeGetItemOverlap(position) {
288
+ const item = this.getItemAtIndex(position);
289
+ const result = this.itemOverlap(item, position);
290
+ this.decoratorBuffer[0] = Length.toDevicePixels(result[0], 0);
291
+ this.decoratorBuffer[1] = Length.toDevicePixels(result[1], 0);
292
+ this.decoratorBuffer[2] = Length.toDevicePixels(result[2], 0);
293
+ this.decoratorBuffer[3] = Length.toDevicePixels(result[3], 0);
294
+ return this.decoratorBuffer;
295
+ }
296
+ [itemOverlapProperty.setNative](value) {
297
+ if (typeof value === 'function') {
298
+ if (!this.decorator) {
299
+ this.decoratorListener = new com.nativescript.collectionview.OverlapDecoration.OverlapDecorationListener({
300
+ getItemOverlap: this.nativeGetItemOverlap.bind(this)
259
301
  });
260
- const scrollListener = new com.nativescript.collectionview.OnScrollListener(this._nScrollListener);
261
- nativeView.addOnScrollListener(scrollListener);
262
- nativeView.scrollListener = scrollListener;
302
+ this.decorator = new com.nativescript.collectionview.OverlapDecoration(this.decoratorListener);
303
+ this.nativeViewProtected.addItemDecoration(this.decorator);
304
+ }
305
+ if (!this.decoratorBuffer) {
306
+ this.decoratorBuffer = createArrayBuffer(4, false, true);
307
+ }
308
+ }
309
+ else {
310
+ if (this.decorator) {
311
+ this.nativeViewProtected.removeItemDecoration(this.decorator);
312
+ this.decorator = null;
263
313
  }
314
+ this.decoratorListener = null;
264
315
  }
265
316
  }
266
- detachScrollListener() {
267
- if (this._scrollOrLoadMoreChangeCount === 0 && this.isLoaded) {
268
- const nativeView = this.nativeViewProtected;
317
+ attachScrollListenerIfNecessary() {
318
+ const nativeView = this.nativeViewProtected;
319
+ if (this._scrollOrLoadMoreChangeCount > 0 && nativeView && !nativeView.scrollListener) {
320
+ this._nScrollListener = new com.nativescript.collectionview.OnScrollListener.Listener({
321
+ onScrollStateChanged: this.onScrollStateChanged.bind(this),
322
+ onScrolled: this.onScrolled.bind(this)
323
+ });
324
+ const scrollListener = new com.nativescript.collectionview.OnScrollListener(this._nScrollListener);
325
+ nativeView.addOnScrollListener(scrollListener);
326
+ nativeView.scrollListener = scrollListener;
327
+ }
328
+ }
329
+ detachScrollListenerIfNecessary(force = false) {
330
+ const nativeView = this.nativeViewProtected;
331
+ if (force || (this._scrollOrLoadMoreChangeCount === 0 && nativeView)) {
269
332
  if (nativeView.scrollListener) {
270
333
  this.nativeView.removeOnScrollListener(nativeView.scrollListener);
271
334
  nativeView.scrollListener = null;
272
- this._nScrollListener = null;
273
335
  }
336
+ this._nScrollListener = null;
274
337
  }
275
338
  }
276
339
  computeScrollEventData(view, eventName, dx, dy) {
@@ -282,6 +345,7 @@ export class CollectionView extends CollectionViewBase {
282
345
  object: this,
283
346
  eventName,
284
347
  scrollOffset: offset / Utils.layout.getDisplayDensity(),
348
+ scrollSize: (range - extent) / Utils.layout.getDisplayDensity(),
285
349
  scrollOffsetPercentage: offset / (range - extent),
286
350
  dx,
287
351
  dy
@@ -306,7 +370,6 @@ export class CollectionView extends CollectionViewBase {
306
370
  const lastVisibleItemPos = layoutManager['findLastCompletelyVisibleItemPosition']();
307
371
  const loadMoreItemIndex = this.items.length - this.loadMoreThreshold;
308
372
  if (lastVisibleItemPos === loadMoreItemIndex) {
309
- this.loadingMore = true;
310
373
  this.notify({ eventName: CollectionViewBase.loadMoreItemsEvent });
311
374
  }
312
375
  }
@@ -321,7 +384,6 @@ export class CollectionView extends CollectionViewBase {
321
384
  }
322
385
  const loadMoreItemIndex = this.items.length - this.loadMoreThreshold;
323
386
  if (lastVisibleItemPos >= loadMoreItemIndex) {
324
- this.loadingMore = true;
325
387
  this.notify({ eventName: CollectionViewBase.loadMoreItemsEvent });
326
388
  }
327
389
  }
@@ -345,14 +407,14 @@ export class CollectionView extends CollectionViewBase {
345
407
  super.addEventListener(arg, callback, thisArg);
346
408
  if (arg === CollectionViewBase.scrollEvent || arg === CollectionViewBase.scrollStartEvent || arg === CollectionViewBase.scrollEndEvent || arg === CollectionViewBase.loadMoreItemsEvent) {
347
409
  this._scrollOrLoadMoreChangeCount++;
348
- this.attachScrollListener();
410
+ this.attachScrollListenerIfNecessary();
349
411
  }
350
412
  }
351
413
  removeEventListener(arg, callback, thisArg) {
352
414
  super.removeEventListener(arg, callback, thisArg);
353
415
  if (arg === CollectionViewBase.scrollEvent || arg === CollectionViewBase.scrollStartEvent || arg === CollectionViewBase.scrollEndEvent || arg === CollectionViewBase.loadMoreItemsEvent) {
354
416
  this._scrollOrLoadMoreChangeCount--;
355
- this.detachScrollListener();
417
+ this.detachScrollListenerIfNecessary();
356
418
  }
357
419
  }
358
420
  //@ts-ignore
@@ -487,6 +549,9 @@ export class CollectionView extends CollectionViewBase {
487
549
  enumerateViewHolders(cb) {
488
550
  let result, v;
489
551
  for (let it = this._viewHolders.values(), cellItemView = null; (cellItemView = it.next().value);) {
552
+ if (cellItemView['position'] === undefined) {
553
+ continue;
554
+ }
490
555
  result = cb(cellItemView);
491
556
  if (result) {
492
557
  return result;
@@ -494,6 +559,19 @@ export class CollectionView extends CollectionViewBase {
494
559
  }
495
560
  return result;
496
561
  }
562
+ async enumerateViewHoldersAsync(cb) {
563
+ let result, v;
564
+ for (let it = this._viewHolders.values(), cellItemView = null; (cellItemView = it.next().value);) {
565
+ if (cellItemView['position'] === undefined) {
566
+ continue;
567
+ }
568
+ result = await cb(cellItemView);
569
+ if (result) {
570
+ return result;
571
+ }
572
+ }
573
+ return result;
574
+ }
497
575
  startDragging(index) {
498
576
  if (this.reorderEnabled && this._itemTouchHelper) {
499
577
  // let viewHolder: CollectionViewCellHolder;
@@ -530,7 +608,7 @@ export class CollectionView extends CollectionViewBase {
530
608
  // we will call events only at then end
531
609
  super._reorderItemInSource(oldPosition, newPosition, false);
532
610
  }
533
- [reorderLongPressEnabledProperty.setNative](value) {
611
+ [_a = reorderLongPressEnabledProperty.setNative](value) {
534
612
  if (value) {
535
613
  if (!this._longPressGesture) {
536
614
  this._longPressGesture = new androidx.core.view.GestureDetectorCompat(this._context, new LongPressGestureListenerImpl(new WeakRef(this)));
@@ -553,7 +631,7 @@ export class CollectionView extends CollectionViewBase {
553
631
  }
554
632
  }
555
633
  }
556
- [reorderingEnabledProperty.setNative](value) {
634
+ [_b = reorderingEnabledProperty.setNative](value) {
557
635
  if (value) {
558
636
  if (!this._simpleItemTouchCallback) {
559
637
  const ItemTouchHelper = androidx.recyclerview.widget.ItemTouchHelper;
@@ -582,50 +660,55 @@ export class CollectionView extends CollectionViewBase {
582
660
  super.onItemTemplatesChanged(oldValue, newValue); // TODO: update current template with the new one
583
661
  this.refresh();
584
662
  }
585
- setOnLayoutChangeListener() {
586
- if (this.nativeViewProtected) {
587
- const owner = this;
588
- this.layoutChangeListenerIsSet = true;
589
- this.layoutChangeListener =
590
- this.layoutChangeListener ||
591
- new android.view.View.OnLayoutChangeListener({
592
- onLayoutChange(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) {
593
- if (left !== oldLeft || top !== oldTop || right !== oldRight || bottom !== oldBottom) {
594
- owner.onLayout(left, top, right, bottom);
595
- if (owner.hasListeners(View.layoutChangedEvent)) {
596
- owner._raiseLayoutChangedEvent();
597
- }
598
- }
599
- }
600
- });
601
- this.nativeViewProtected.addOnLayoutChangeListener(this.layoutChangeListener);
663
+ updateSpanCount(requestLayout = true) {
664
+ if (this.mInPropertiesSet) {
665
+ this.mShouldUpdateSpanCount = true;
666
+ return false;
602
667
  }
603
- }
604
- _updateSpanCount() {
668
+ this.mShouldUpdateSpanCount = false;
605
669
  const layoutManager = this.layoutManager;
606
670
  if (layoutManager && layoutManager['setSpanCount']) {
607
671
  const newValue = (this.currentSpanCount = this.computeSpanCount());
608
672
  if (newValue !== layoutManager['getSpanCount']()) {
609
673
  layoutManager['setSpanCount'](newValue);
610
- layoutManager.requestLayout();
674
+ if (requestLayout) {
675
+ layoutManager.requestLayout();
676
+ }
677
+ return true;
611
678
  }
612
679
  }
680
+ return false;
613
681
  }
614
682
  updateInnerSize() {
615
- super.updateInnerSize();
616
- this._updateSpanCount();
683
+ if (this.mInPropertiesSet) {
684
+ this.mShouldUpdateInnerSize = true;
685
+ return false;
686
+ }
687
+ this.mShouldUpdateInnerSize = false;
688
+ const result = super.updateInnerSize();
689
+ if (result) {
690
+ this.updateSpanCount();
691
+ }
692
+ // there is no need to call refresh if it was triggered before with same size.
693
+ // this refresh is just to handle size change
694
+ const layoutKey = this._innerWidth + '_' + this._innerHeight;
695
+ if (this._isDataDirty || (this._lastLayoutKey && this._lastLayoutKey !== layoutKey)) {
696
+ // setTimeout(() => this.refresh(false), 0);
697
+ }
698
+ this._lastLayoutKey = layoutKey;
699
+ return result;
617
700
  }
618
701
  _onColWidthPropertyChanged(oldValue, newValue) {
619
- this._updateSpanCount();
702
+ this.updateSpanCount();
620
703
  super._onColWidthPropertyChanged(oldValue, newValue);
621
704
  }
622
705
  _onRowHeightPropertyChanged(oldValue, newValue) {
623
- this._updateSpanCount();
706
+ this.updateSpanCount();
624
707
  super._onRowHeightPropertyChanged(oldValue, newValue);
625
708
  }
626
709
  onLayout(left, top, right, bottom) {
627
710
  this._layedOut = true;
628
- super.onLayout(left, top, right, bottom);
711
+ // super.onLayout(left, top, right, bottom);
629
712
  const p = CollectionViewBase.plugins[this.layoutStyle];
630
713
  if (p && p.onLayout) {
631
714
  p.onLayout(this, left, top, right, bottom);
@@ -634,13 +717,30 @@ export class CollectionView extends CollectionViewBase {
634
717
  const p = CollectionViewBase.plugins[k];
635
718
  p.onLayout && p.onLayout(this, left, top, right, bottom);
636
719
  });
637
- // there is no need to call refresh if it was triggered before with same size.
638
- // this refresh is just to handle size change
639
- const layoutKey = this._innerWidth + '_' + this._innerHeight;
640
- if (this._isDataDirty || (this._lastLayoutKey && this._lastLayoutKey !== layoutKey)) {
641
- setTimeout(() => this.refresh(), 0);
720
+ }
721
+ onMeasure(widthMeasureSpec, heightMeasureSpec) {
722
+ const lastLayoutKey = this._lastLayoutKey;
723
+ this.updateInnerSize();
724
+ if (lastLayoutKey !== this._lastLayoutKey) {
725
+ //we need to refresh visible cells so that they measure to the new size
726
+ // for some reason it gets animated even with setSupportsChangeAnimations(false)
727
+ // so we clear until it is done
728
+ const nativeView = this.nativeViewProtected;
729
+ const animator = nativeView.getItemAnimator();
730
+ nativeView.setItemAnimator(null);
731
+ this.refreshVisibleItems();
732
+ setTimeout(() => {
733
+ nativeView.setItemAnimator(animator);
734
+ }, 0);
642
735
  }
643
- this._lastLayoutKey = layoutKey;
736
+ const p = CollectionViewBase.plugins[this.layoutStyle];
737
+ if (p && p.onMeasure) {
738
+ p.onMeasure(this, widthMeasureSpec, heightMeasureSpec);
739
+ }
740
+ this.plugins.forEach((k) => {
741
+ const p = CollectionViewBase.plugins[k];
742
+ p.onMeasure && p.onMeasure(this, widthMeasureSpec, heightMeasureSpec);
743
+ });
644
744
  }
645
745
  onSourceCollectionChanged(event) {
646
746
  if (!this._listViewAdapter || this._dataUpdatesSuspended) {
@@ -708,7 +808,6 @@ export class CollectionView extends CollectionViewBase {
708
808
  }
709
809
  }
710
810
  this._listViewAdapter.notifyDataSetChanged();
711
- this.loadingMore = false;
712
811
  }
713
812
  eachChild(callback) {
714
813
  // used for css updates (like theme change)
@@ -727,15 +826,28 @@ export class CollectionView extends CollectionViewBase {
727
826
  }
728
827
  });
729
828
  }
829
+ async eachChildAsync(callback) {
830
+ return this.enumerateViewHoldersAsync(async (v) => {
831
+ const view = v.view;
832
+ if (view) {
833
+ if (view.parent instanceof CollectionView) {
834
+ await callback(view);
835
+ }
836
+ else {
837
+ // in some cases (like item is unloaded from another place (like angular) view.parent becomes undefined)
838
+ if (view.parent) {
839
+ await callback(view.parent);
840
+ }
841
+ }
842
+ }
843
+ });
844
+ }
730
845
  refreshVisibleItems() {
731
846
  const view = this.nativeViewProtected;
732
847
  if (!view) {
733
848
  return;
734
849
  }
735
- const ids = Array.from(this._viewHolders)
736
- .map((s) => s['position'])
737
- .filter((s) => s !== null)
738
- .sort((a, b) => a - b);
850
+ const ids = Array.from(this.bindedViewHolders).sort((a, b) => a - b);
739
851
  this._listViewAdapter.notifyItemRangeChanged(ids[0], ids[ids.length - 1] - ids[0] + 1);
740
852
  }
741
853
  isItemAtIndexVisible(index) {
@@ -751,12 +863,41 @@ export class CollectionView extends CollectionViewBase {
751
863
  }
752
864
  return false;
753
865
  }
754
- refresh() {
755
- if (!this.nativeViewProtected) {
866
+ findFirstVisibleItemIndex() {
867
+ const view = this.nativeViewProtected;
868
+ if (!view) {
869
+ return -1;
870
+ }
871
+ const layoutManager = this.layoutManager;
872
+ if (layoutManager['findFirstVisibleItemPosition']) {
873
+ return layoutManager.findFirstVisibleItemPosition();
874
+ }
875
+ return -1;
876
+ }
877
+ findLastVisibleItemIndex() {
878
+ const view = this.nativeViewProtected;
879
+ if (!view) {
880
+ return -1;
881
+ }
882
+ const layoutManager = this.layoutManager;
883
+ if (layoutManager['findLastVisibleItemPosition']) {
884
+ return layoutManager.findLastVisibleItemPosition();
885
+ }
886
+ return -1;
887
+ }
888
+ refresh(forceRefresh = false, updateSpanCountRequestsLayout = false) {
889
+ if (this.mInPropertiesSet) {
890
+ this.mShouldRefresh = true;
756
891
  return;
757
892
  }
893
+ this.mShouldRefresh = false;
758
894
  const view = this.nativeViewProtected;
759
- if (!this.isLoaded) {
895
+ if (!view) {
896
+ return;
897
+ }
898
+ // seems like we refresh sooner
899
+ // not sure why it was needed before and not now.
900
+ if (!forceRefresh && (!this.isLoaded || !this.nativeView)) {
760
901
  this._isDataDirty = true;
761
902
  return;
762
903
  }
@@ -764,14 +905,14 @@ export class CollectionView extends CollectionViewBase {
764
905
  this._lastLayoutKey = this._innerWidth + '_' + this._innerHeight;
765
906
  let adapter = this._listViewAdapter;
766
907
  if (!adapter) {
767
- adapter = this._listViewAdapter = this.createComposedAdapter(this.nativeViewProtected);
908
+ adapter = this._listViewAdapter = this.createComposedAdapter(view);
768
909
  adapter.setHasStableIds(!!this._itemIdGenerator);
769
910
  view.setAdapter(adapter);
770
911
  }
771
912
  else if (!view.getAdapter()) {
772
913
  view.setAdapter(adapter);
773
914
  }
774
- this._updateSpanCount();
915
+ this.updateSpanCount(updateSpanCountRequestsLayout);
775
916
  adapter.notifyDataSetChanged();
776
917
  this.notify({ eventName: CollectionViewBase.dataPopulatedEvent });
777
918
  }
@@ -797,23 +938,27 @@ export class CollectionView extends CollectionViewBase {
797
938
  }
798
939
  return view.computeVerticalScrollOffset() / Utils.layout.getDisplayDensity();
799
940
  }
800
- scrollToIndex(index, animated = true) {
801
- if (!this.nativeViewProtected) {
941
+ scrollToIndex(index, animated = true, snap = SnapPosition.START) {
942
+ const view = this.nativeViewProtected;
943
+ if (!view) {
802
944
  return;
803
945
  }
804
946
  if (animated) {
805
- this.nativeViewProtected.smoothScrollToPosition(index);
947
+ view.smoothScrollToPosition(index, snap);
806
948
  }
807
949
  else {
808
- this.nativeViewProtected.scrollToPosition(index);
950
+ view.scrollToPosition(index);
809
951
  }
810
952
  }
811
953
  scrollToOffset(offSetValue) {
812
- if (this.nativeViewProtected && this.orientation === 'horizontal' && this.isScrollEnabled) {
813
- this.nativeViewProtected.scrollBy(offSetValue, 0);
814
- }
815
- if (this.nativeViewProtected && this.orientation === 'vertical' && this.isScrollEnabled) {
816
- this.nativeViewProtected.scrollBy(0, offSetValue);
954
+ const view = this.nativeViewProtected;
955
+ if (view && this.isScrollEnabled) {
956
+ if (this.orientation === 'horizontal') {
957
+ view.scrollBy(offSetValue, 0);
958
+ }
959
+ else {
960
+ view.scrollBy(0, offSetValue);
961
+ }
817
962
  }
818
963
  }
819
964
  _setPadding(newPadding) {
@@ -914,23 +1059,26 @@ export class CollectionView extends CollectionViewBase {
914
1059
  }
915
1060
  return this.templateTypeNumberString.get(key);
916
1061
  }
917
- nativeItemToTemplateKey(item) {
918
- let result;
919
- this.templateTypeNumberString?.forEach((value, key, map) => {
920
- if (value === item) {
921
- result = key;
922
- }
923
- }, this);
924
- return result;
925
- }
1062
+ // public nativeItemToTemplateKey(item: number): string {
1063
+ // let result: string;
1064
+ // this.templateTypeNumberString?.forEach((value, key, map) => {
1065
+ // if (value === item) {
1066
+ // result = key;
1067
+ // }
1068
+ // }, this);
1069
+ // return result;
1070
+ // }
926
1071
  disposeViewHolderViews() {
927
1072
  this.enumerateViewHolders((v) => {
928
1073
  const view = v.view;
929
- if (view && view.isLoaded) {
930
- view.callUnloaded();
1074
+ if (view) {
1075
+ this.notifyForItemAtIndex(CollectionViewBase.itemDisposingEvent, view, v.getAdapterPosition(), view.bindingContext, v);
1076
+ if (view.isLoaded) {
1077
+ view.callUnloaded();
1078
+ }
1079
+ view._isAddedToNativeVisualTree = false;
1080
+ view._tearDownUI();
931
1081
  }
932
- view._isAddedToNativeVisualTree = false;
933
- view._tearDownUI();
934
1082
  v.view = null;
935
1083
  v.clickListener = null;
936
1084
  });
@@ -940,7 +1088,8 @@ export class CollectionView extends CollectionViewBase {
940
1088
  return this.templateStringTypeNumber.get(viewType);
941
1089
  }
942
1090
  onCreateViewHolder(parent, viewType) {
943
- let view = this.getViewForTemplateType(this.getKeyByValue(viewType), ViewTemplateType.Item);
1091
+ const start = Date.now();
1092
+ let view = this.getViewForViewType(ListViewViewTypes.ItemView, this.getKeyByValue(viewType));
944
1093
  const isNonSync = view === undefined;
945
1094
  // dont create unecessary StackLayout if template.createView returns. Will happend when not using Vue or angular
946
1095
  if (isNonSync || view instanceof ProxyViewContainer) {
@@ -948,10 +1097,10 @@ export class CollectionView extends CollectionViewBase {
948
1097
  parentView.id = 'collectionViewHolder';
949
1098
  view = parentView;
950
1099
  }
951
- view._setupAsRootView(this._context);
952
- view._isAddedToNativeVisualTree = true;
953
1100
  //@ts-ignore
954
1101
  view.parent = this;
1102
+ view._setupAsRootView(this._context);
1103
+ view._isAddedToNativeVisualTree = true;
955
1104
  view.callLoaded();
956
1105
  if (!CollectionViewCellHolder) {
957
1106
  CollectionViewCellHolder = com.nativescript.collectionview.CollectionViewCellHolder;
@@ -980,7 +1129,7 @@ export class CollectionView extends CollectionViewBase {
980
1129
  }
981
1130
  this._viewHolders.add(holder);
982
1131
  if (Trace.isEnabled()) {
983
- CLog(CLogTypes.log, 'onCreateViewHolder', viewType, this.getKeyByValue(viewType));
1132
+ CLog(CLogTypes.log, 'onCreateViewHolder', this, this.nativeView, viewType, this.getKeyByValue(viewType), holder, Date.now() - start, 'ms');
984
1133
  }
985
1134
  return holder;
986
1135
  }
@@ -990,14 +1139,19 @@ export class CollectionView extends CollectionViewBase {
990
1139
  return args;
991
1140
  }
992
1141
  onBindViewHolder(holder, position) {
1142
+ const start = Date.now();
993
1143
  if (Trace.isEnabled()) {
994
- CLog(CLogTypes.log, 'onBindViewHolder', position);
1144
+ CLog(CLogTypes.log, 'onBindViewHolder', this, this.nativeView, position, holder, holder.view);
995
1145
  }
996
1146
  let view = holder.view;
997
1147
  const isNonSync = holder['defaultItemView'] === true;
998
1148
  view = isNonSync ? view.content : view;
999
1149
  const bindingContext = this._prepareItem(view, position);
1150
+ if (holder['position'] !== undefined) {
1151
+ this.bindedViewHolders.delete(holder['position']);
1152
+ }
1000
1153
  holder['position'] = position;
1154
+ this.bindedViewHolders.add(holder['position']);
1001
1155
  const args = this.notifyForItemAtIndex(CollectionViewBase.itemLoadingEvent, view, position, bindingContext, holder);
1002
1156
  if (isNonSync && args.view !== view) {
1003
1157
  view = args.view;
@@ -1024,21 +1178,23 @@ export class CollectionView extends CollectionViewBase {
1024
1178
  if (height || !view.height) {
1025
1179
  view.height = Utils.layout.toDeviceIndependentPixels(height);
1026
1180
  }
1027
- // if (this.hasListeners(CollectionViewBase.displayItemEvent) ) {
1028
- // this.notify<CollectionViewItemDisplayEventData>({
1029
- // eventName: CollectionViewBase.displayItemEvent,
1030
- // index:position,
1031
- // object: this,
1032
- // });
1033
- // }
1181
+ if (this.hasListeners(CollectionViewBase.displayItemEvent)) {
1182
+ this.notify({
1183
+ eventName: CollectionViewBase.displayItemEvent,
1184
+ index: position,
1185
+ object: this
1186
+ });
1187
+ }
1034
1188
  if (Trace.isEnabled()) {
1035
- CLog(CLogTypes.log, 'onBindViewHolder done ', position);
1189
+ CLog(CLogTypes.log, 'onBindViewHolder done ', position, Date.now() - start, 'ms');
1036
1190
  }
1037
1191
  }
1038
1192
  onViewRecycled(holder) {
1039
- holder['position'] = null;
1193
+ delete this.bindedViewHolders[holder['position']];
1194
+ holder['position'] = undefined;
1040
1195
  }
1041
1196
  }
1197
+ CollectionView.layoutCompletedEvent = 'layoutCompleted';
1042
1198
  CollectionView.DEFAULT_TEMPLATE_VIEW_TYPE = 0;
1043
1199
  CollectionView.CUSTOM_TEMPLATE_ITEM_TYPE = 1;
1044
1200
  __decorate([
@@ -1058,19 +1214,153 @@ __decorate([
1058
1214
  __metadata("design:type", Function),
1059
1215
  __metadata("design:paramtypes", []),
1060
1216
  __metadata("design:returntype", void 0)
1217
+ ], CollectionView.prototype, "disposeNativeView", null);
1218
+ __decorate([
1219
+ profile,
1220
+ __metadata("design:type", Function),
1221
+ __metadata("design:paramtypes", [String, Number]),
1222
+ __metadata("design:returntype", void 0)
1223
+ ], CollectionView.prototype, "setNativePoolSize", null);
1224
+ __decorate([
1225
+ profile,
1226
+ __metadata("design:type", Function),
1227
+ __metadata("design:paramtypes", []),
1228
+ __metadata("design:returntype", void 0)
1229
+ ], CollectionView.prototype, "setPoolSizes", null);
1230
+ __decorate([
1231
+ profile,
1232
+ __metadata("design:type", Function),
1233
+ __metadata("design:paramtypes", [Boolean]),
1234
+ __metadata("design:returntype", void 0)
1235
+ ], CollectionView.prototype, _a, null);
1236
+ __decorate([
1237
+ profile,
1238
+ __metadata("design:type", Function),
1239
+ __metadata("design:paramtypes", [Boolean]),
1240
+ __metadata("design:returntype", void 0)
1241
+ ], CollectionView.prototype, _b, null);
1242
+ __decorate([
1243
+ profile,
1244
+ __metadata("design:type", Function),
1245
+ __metadata("design:paramtypes", []),
1246
+ __metadata("design:returntype", void 0)
1247
+ ], CollectionView.prototype, "onItemViewLoaderChanged", null);
1248
+ __decorate([
1249
+ profile,
1250
+ __metadata("design:type", Function),
1251
+ __metadata("design:paramtypes", [Object, Object]),
1252
+ __metadata("design:returntype", void 0)
1253
+ ], CollectionView.prototype, "onItemTemplateSelectorChanged", null);
1254
+ __decorate([
1255
+ profile,
1256
+ __metadata("design:type", Function),
1257
+ __metadata("design:paramtypes", [Object, Object]),
1258
+ __metadata("design:returntype", void 0)
1259
+ ], CollectionView.prototype, "onItemTemplateChanged", null);
1260
+ __decorate([
1261
+ profile,
1262
+ __metadata("design:type", Function),
1263
+ __metadata("design:paramtypes", [Object, Object]),
1264
+ __metadata("design:returntype", void 0)
1265
+ ], CollectionView.prototype, "onItemTemplatesChanged", null);
1266
+ __decorate([
1267
+ profile,
1268
+ __metadata("design:type", Function),
1269
+ __metadata("design:paramtypes", [Object]),
1270
+ __metadata("design:returntype", void 0)
1271
+ ], CollectionView.prototype, "updateSpanCount", null);
1272
+ __decorate([
1273
+ profile,
1274
+ __metadata("design:type", Function),
1275
+ __metadata("design:paramtypes", []),
1276
+ __metadata("design:returntype", void 0)
1277
+ ], CollectionView.prototype, "updateInnerSize", null);
1278
+ __decorate([
1279
+ profile,
1280
+ __metadata("design:type", Function),
1281
+ __metadata("design:paramtypes", [Object, Object]),
1282
+ __metadata("design:returntype", void 0)
1283
+ ], CollectionView.prototype, "_onColWidthPropertyChanged", null);
1284
+ __decorate([
1285
+ profile,
1286
+ __metadata("design:type", Function),
1287
+ __metadata("design:paramtypes", [Object, Object]),
1288
+ __metadata("design:returntype", void 0)
1289
+ ], CollectionView.prototype, "_onRowHeightPropertyChanged", null);
1290
+ __decorate([
1291
+ profile,
1292
+ __metadata("design:type", Function),
1293
+ __metadata("design:paramtypes", [Number, Number, Number, Number]),
1294
+ __metadata("design:returntype", void 0)
1295
+ ], CollectionView.prototype, "onLayout", null);
1296
+ __decorate([
1297
+ profile,
1298
+ __metadata("design:type", Function),
1299
+ __metadata("design:paramtypes", [Number, Number]),
1300
+ __metadata("design:returntype", void 0)
1301
+ ], CollectionView.prototype, "onMeasure", null);
1302
+ __decorate([
1303
+ profile,
1304
+ __metadata("design:type", Function),
1305
+ __metadata("design:paramtypes", [Object, Object]),
1306
+ __metadata("design:returntype", void 0)
1061
1307
  ], CollectionView.prototype, "refresh", null);
1308
+ __decorate([
1309
+ profile,
1310
+ __metadata("design:type", Function),
1311
+ __metadata("design:paramtypes", [Object]),
1312
+ __metadata("design:returntype", void 0)
1313
+ ], CollectionView.prototype, "_setPadding", null);
1314
+ __decorate([
1315
+ profile,
1316
+ __metadata("design:type", Function),
1317
+ __metadata("design:paramtypes", [Object]),
1318
+ __metadata("design:returntype", void 0)
1319
+ ], CollectionView.prototype, "createComposedAdapter", null);
1320
+ __decorate([
1321
+ profile,
1322
+ __metadata("design:type", Function),
1323
+ __metadata("design:paramtypes", []),
1324
+ __metadata("design:returntype", void 0)
1325
+ ], CollectionView.prototype, "clearTemplateTypes", null);
1326
+ __decorate([
1327
+ profile,
1328
+ __metadata("design:type", Function),
1329
+ __metadata("design:paramtypes", [Number]),
1330
+ __metadata("design:returntype", void 0)
1331
+ ], CollectionView.prototype, "getItemViewType", null);
1332
+ __decorate([
1333
+ profile,
1334
+ __metadata("design:type", Function),
1335
+ __metadata("design:paramtypes", [String]),
1336
+ __metadata("design:returntype", Number)
1337
+ ], CollectionView.prototype, "templateKeyToNativeItem", null);
1338
+ __decorate([
1339
+ profile,
1340
+ __metadata("design:type", Function),
1341
+ __metadata("design:paramtypes", []),
1342
+ __metadata("design:returntype", void 0)
1343
+ ], CollectionView.prototype, "disposeViewHolderViews", null);
1062
1344
  __decorate([
1063
1345
  profile,
1064
1346
  __metadata("design:type", Function),
1065
1347
  __metadata("design:paramtypes", [android.view.ViewGroup, Number]),
1066
1348
  __metadata("design:returntype", void 0)
1067
1349
  ], CollectionView.prototype, "onCreateViewHolder", null);
1350
+ __decorate([
1351
+ profile,
1352
+ __metadata("design:type", Function),
1353
+ __metadata("design:paramtypes", [String, View, Number, Object, Object]),
1354
+ __metadata("design:returntype", void 0)
1355
+ ], CollectionView.prototype, "notifyForItemAtIndex", null);
1068
1356
  __decorate([
1069
1357
  profile,
1070
1358
  __metadata("design:type", Function),
1071
1359
  __metadata("design:paramtypes", [CollectionViewCellHolder, Number]),
1072
1360
  __metadata("design:returntype", void 0)
1073
1361
  ], CollectionView.prototype, "onBindViewHolder", null);
1362
+ let CollectionViewCellHolder;
1363
+ let CollectionViewRecyclerView;
1074
1364
  itemViewCacheSizeProperty.register(CollectionViewBase);
1075
1365
  extraLayoutSpaceProperty.register(CollectionViewBase);
1076
1366
  nestedScrollingEnabledProperty.register(CollectionViewBase);