UNPKG

@nativescript-community/ui-pager

Version:

A NativeScript Pager / Carousel component that allows the user to swipe left and right through pages of data.

1,162 lines (1,161 loc) 53.2 kB
import { ChangeType, Observable, Property, ProxyViewContainer, StackLayout, Utils, View, profile } from '@nativescript/core'; import { paddingBottomProperty, paddingLeftProperty, paddingRightProperty, paddingTopProperty } from '@nativescript/core/ui/styling/style-properties'; import { PagerBase, autoPlayProperty, autoplayDelayProperty, disableSwipeProperty, itemTemplatesProperty, itemsProperty, orientationProperty, selectedIndexProperty } from './index.common'; export * from './index.common'; export { Transformer } from './index.common'; const main_queue = dispatch_get_current_queue(); export var ContentInsetAdjustmentBehavior; (function (ContentInsetAdjustmentBehavior) { ContentInsetAdjustmentBehavior[ContentInsetAdjustmentBehavior["Always"] = 3] = "Always"; ContentInsetAdjustmentBehavior[ContentInsetAdjustmentBehavior["Automatic"] = 0] = "Automatic"; ContentInsetAdjustmentBehavior[ContentInsetAdjustmentBehavior["Never"] = 2] = "Never"; ContentInsetAdjustmentBehavior[ContentInsetAdjustmentBehavior["ScrollableAxes"] = 1] = "ScrollableAxes"; })(ContentInsetAdjustmentBehavior || (ContentInsetAdjustmentBehavior = {})); function parseContentInsetAdjustmentBehavior(value) { if (typeof value === 'string') { switch (value) { case 'always': return ContentInsetAdjustmentBehavior.Always; case 'never': return ContentInsetAdjustmentBehavior.Never; case 'scrollableAxes': return ContentInsetAdjustmentBehavior.ScrollableAxes; default: case 'automatic': return ContentInsetAdjustmentBehavior.Automatic; } } else { return value; } } export const contentInsetAdjustmentBehaviorProperty = new Property({ name: 'contentInsetAdjustmentBehavior', valueConverter: parseContentInsetAdjustmentBehavior, defaultValue: ContentInsetAdjustmentBehavior.Automatic }); var UICellView = /** @class */ (function (_super) { __extends(UICellView, _super); function UICellView() { return _super !== null && _super.apply(this, arguments) || this; } UICellView.prototype.layoutSubviews = function () { var view = this.view && this.view.get(); if (!view) { return; } this.frame = this.superview.bounds; var size = this.bounds.size; View.layoutChild(null, view, 0, 0, Utils.layout.toDevicePixels(size.width), Utils.layout.toDevicePixels(size.height)); }; return UICellView; }(UIView)); const PFLAG_FORCE_LAYOUT = 1; export class Pager extends PagerBase { constructor() { super(); this.lastEvent = 0; this.mDisableSwipe = false; this.mDisableAnimation = false; this.mPreparingCell = false; this.mIsRefreshing = false; this.mIsInit = false; this._observableArrayHandler = (args) => { if (!this.nativeViewProtected) { return; } if (this.indicator && this.mObservableArrayInstance && this.mObservableArrayInstance.length) { this.indicator.setCount(this.mObservableArrayInstance.length); } const collectionView = this.nativeViewProtected; if (collectionView) { try { let offset = 0; collectionView.performBatchUpdatesCompletion(() => { this.mIsRefreshing = true; const array = []; switch (args.action) { case ChangeType.Add: for (let i = 0; i < args.addedCount; i++) { array.push(NSIndexPath.indexPathForRowInSection(args.index + i, 0)); } offset = collectionView.contentSize.width - collectionView.contentOffset.x; collectionView.insertItemsAtIndexPaths(array); break; case ChangeType.Delete: for (let i = 0; i < args.removed.length; i++) { array.push(NSIndexPath.indexPathForItemInSection(args.index + i, 0)); } collectionView.deleteItemsAtIndexPaths(array); break; case ChangeType.Splice: if (args.removed && args.removed.length > 0) { for (let i = 0; i < args.removed.length; i++) { array.push(NSIndexPath.indexPathForRowInSection(args.index + i, 0)); } collectionView.deleteItemsAtIndexPaths(array); } if (args.addedCount > 0) { const addedArray = []; for (let i = 0; i < args.addedCount; i++) { addedArray.push(NSIndexPath.indexPathForRowInSection(args.index + i, 0)); } collectionView.insertItemsAtIndexPaths(addedArray); } break; case ChangeType.Update: collectionView.reloadItemsAtIndexPaths([NSIndexPath.indexPathForRowInSection(args.index, 0)]); break; default: break; } this._initAutoPlay(this.autoPlay); if (this.itemCount === 0) { this.mIsInit = false; selectedIndexProperty.nativeValueChange(this, -1); } }, () => { if (collectionView.indexPathsForVisibleItems.count > 0) { const currentIndex = collectionView.indexPathsForVisibleItems.objectAtIndex(0).item; selectedIndexProperty.nativeValueChange(this, this.getPosition(currentIndex)); } }); } catch (err) { } } }; this._isDataDirty = false; this.mMap = new Map(); } createNativeView() { this.mLayout = UICollectionViewFlowLinearLayoutImpl.initWithOwner(new WeakRef(this)); this.mLayout.scrollDirection = 1 /* UICollectionViewScrollDirection.Horizontal */; this.mLayout.minimumInteritemSpacing = 0; const nativeView = UICollectionView.alloc().initWithFrameCollectionViewLayout(CGRectZero, this.mLayout); nativeView.backgroundColor = UIColor.clearColor; nativeView.autoresizesSubviews = false; nativeView.autoresizingMask = 0 /* UIViewAutoresizing.None */; nativeView.showsHorizontalScrollIndicator = false; nativeView.showsVerticalScrollIndicator = false; nativeView.decelerationRate = UIScrollViewDecelerationRateFast; this._itemTemplatesInternal.forEach((t) => { nativeView.registerClassForCellWithReuseIdentifier(PagerCell.class(), t.key); }); return nativeView; } initNativeView() { super.initNativeView(); const nativeView = this.nativeViewProtected; nativeView.registerClassForCellWithReuseIdentifier(PagerCell.class(), this._defaultTemplate.key); nativeView.backgroundColor = UIColor.clearColor; nativeView.autoresizesSubviews = false; nativeView.autoresizingMask = 0; nativeView.dataSource = this.mDataSource = UICollectionViewDataSourceImpl.initWithOwner(new WeakRef(this)); nativeView.scrollEnabled = !this.disableSwipe; if (this.orientation === 'vertical') { this.mLayout.scrollDirection = 0 /* UICollectionViewScrollDirection.Vertical */; nativeView.alwaysBounceVertical = true; nativeView.alwaysBounceHorizontal = false; } else { this.mLayout.scrollDirection = 1 /* UICollectionViewScrollDirection.Horizontal */; nativeView.alwaysBounceHorizontal = true; nativeView.alwaysBounceVertical = false; } this.mDelegate = UICollectionDelegateImpl.initWithOwner(new WeakRef(this)); this._setNativeClipToBounds(); this._initAutoPlay(this.autoPlay); } getChildView(index) { if (this._childrenViews) { return this._childrenViews[index]?.view; } let result; if (this.nativeViewProtected) { const cell = this.nativeViewProtected.cellForItemAtIndexPath(NSIndexPath.indexPathForRowInSection(index, 0)); return cell?.view; } return result; } getViewForItemAtIndex(index) { return this.getChildView(index); } _getRealWidthHeight() { let height = 0; let width = 0; width = (Utils.layout.toDeviceIndependentPixels(this._effectiveItemWidth) - (this.perPage * 2 * this._getSpacing() + this._getPeaking() * 2)) / this.perPage; height = (Utils.layout.toDeviceIndependentPixels(this._effectiveItemHeight) - (this.perPage * 2 * this._getSpacing() + this._getPeaking() * 2)) / this.perPage; return { height, width }; } _nextIndex() { if (this.circularMode) { // TODO return 0; } else { const next = this.selectedIndex + 1; if (next > this.lastIndex) { return 0; } return next; } } _initAutoPlay(value) { if (!this.items || this.items.length === 0) { return; } if (!value) { if (this._autoPlayInterval) { clearInterval(this._autoPlayInterval); this._autoPlayInterval = undefined; } } else { if (this.isLayoutValid && !this._autoPlayInterval) { this._autoPlayInterval = setInterval(() => { this.selectedIndex = this._nextIndex(); }, this.autoPlayDelay); } } } /** * * Get the selected index from the position in the CollectionView * * @param index The position in the collectionView * @returns The selected Index ( i.e. the number in the slides as the user would view it). */ getPosition(index) { let position = index; if (this.circularMode) { if (position === 0) { position = this.lastDummy; } else if (position === this.firstDummy) { position = 0; } else { position = position - 1; } } return position; } /** * * Get the position in the CollectionView from the selected index * * @param index The position in the collectionView * @returns The selected Index ( i.e. the number in the slides as the user would view it). */ getIndex(index) { let position = index; if (this.circularMode) { if (position === 0) { position = 1; } else if (position === this.firstDummy) { position = 0; } else { position = position + 1; } } return position; } animateForFlip(index) { if (!this.circularMode) { return true; } if (index !== this.firstDummy && index !== 0) { return true; } return false; } get itemCount() { return this._childrenCount ? this._childrenCount + (this.circularMode ? 2 : 0) : 0; } get lastIndex() { return Math.max(0, this.circularMode ? this.itemCount - 3 : this.itemCount - 1); } get firstDummy() { return Math.max(0, this.itemCount - 1); } get lastDummy() { return this.lastIndex; } get _childrenCount() { return this.items?.length ?? this._childrenViews?.length ?? 0; } itemTemplateUpdated(oldData, newData) { } _setNativeClipToBounds() { this.nativeViewProtected.clipsToBounds = true; } [orientationProperty.setNative](value) { if (value === 'horizontal') { this.mLayout.scrollDirection = 1 /* UICollectionViewScrollDirection.Horizontal */; } else { this.mLayout.scrollDirection = 0 /* UICollectionViewScrollDirection.Vertical */; } } eachChildView(callback) { this.mMap.forEach((view, key) => callback(view)); } eachChild(callback) { this.mMap.forEach((view, key) => callback(view)); } _updateScrollPosition() { const view = this.nativeViewProtected; if (!view) { return; } const size = this.orientation === 'vertical' ? view.contentSize.height : view.contentSize.width; if (size === 0) { return; } this.scrollToIndexAnimated(this.selectedIndex, false); } [selectedIndexProperty.setNative](value, animated = true) { if (this.isLoaded) { this.scrollToIndexAnimated(value, animated && !this.disableAnimation); } } [itemTemplatesProperty.getDefault]() { return null; } [itemTemplatesProperty.setNative](value) { this._itemTemplatesInternal = new Array(this._defaultTemplate); if (value) { for (let i = 0, length = value.length; i < length; i++) { this.nativeViewProtected.registerClassForCellWithReuseIdentifier(PagerCell.class(), value[i].key); } this._itemTemplatesInternal = this._itemTemplatesInternal.concat(value); } } [itemsProperty.setNative](value) { if (this.indicator && value && value.length) { this.indicator.setCount(value.length); } this.setObservableArrayInstance(value); if (!value) { this.mIsInit = false; } } [autoPlayProperty.setNative](value) { this._initAutoPlay(value); } [autoplayDelayProperty.setNative](value) { if (this._autoPlayInterval) { clearInterval(this._autoPlayInterval); this._autoPlayInterval = undefined; this._initAutoPlay(this.autoPlay); } } _setPadding(newPadding) { const layout = this.nativeViewProtected; const sectionInset = layout['contentInset']; const padding = { top: sectionInset.top, right: sectionInset.right, bottom: sectionInset.bottom, left: sectionInset.left }; const newValue = Object.assign(padding, newPadding); layout['contentInset'] = newValue; } [paddingTopProperty.setNative](value) { this._setPadding({ top: Utils.layout.toDeviceIndependentPixels(this.effectivePaddingTop) }); } [paddingRightProperty.setNative](value) { this._setPadding({ right: Utils.layout.toDeviceIndependentPixels(this.effectivePaddingRight) }); } [paddingBottomProperty.setNative](value) { this._setPadding({ bottom: Utils.layout.toDeviceIndependentPixels(this.effectivePaddingBottom) }); } [paddingLeftProperty.setNative](value) { this._setPadding({ left: Utils.layout.toDeviceIndependentPixels(this.effectivePaddingLeft) }); } _onItemsChanged(oldValue, newValue) { } scrollToIndexAnimated(index, animate) { if (!this.nativeViewProtected) return; const contentSize = this.nativeViewProtected.contentSize; const size = this.orientation === 'vertical' ? contentSize.height : contentSize.width; if (size === 0) { return; } if (this._childrenCount === 0) { return; } const maxMinIndex = Math.min(Math.max(0, index), this._childrenCount - 1); let isNativeValueChanged = false; if (!this.isLoaded) { isNativeValueChanged = true; } else { const page = this.page; const frame = page && page.frame; if (frame) { if (frame._executingContext) { isNativeValueChanged = frame._executingContext.entry.resolvedPage !== page; } else { isNativeValueChanged = frame.currentPage !== page; } } } if (isNativeValueChanged) { return selectedIndexProperty.nativeValueChange(this, maxMinIndex); } // dispatch_async(main_queue, () => { if (this.mDataSource.collectionViewNumberOfItemsInSection(this.nativeViewProtected, 0) > maxMinIndex) { // when we have custom layouts (they don't occupy 100% of the parent) and we use custom transformers we need to call setContentOffsetAnimated to take size into account. // Reference: https://stackoverflow.com/a/53798708/6015400 this.nativeViewProtected.setContentOffsetAnimated(CGPointMake(1, 0), !!animate); this.nativeViewProtected.scrollToItemAtIndexPathAtScrollPositionAnimated(NSIndexPath.indexPathForItemInSection(this.getIndex(maxMinIndex), 0), this.orientation === 'vertical' ? 2 /* UICollectionViewScrollPosition.CenteredVertically */ : 16 /* UICollectionViewScrollPosition.CenteredHorizontally */, !!animate); } selectedIndexProperty.nativeValueChange(this, maxMinIndex); // }); } refresh(delayUpdateScrollPosition = false) { if (!this.isLoaded || !this.nativeView) { this._isDataDirty = true; return; } this._isDataDirty = false; this.mLastLayoutKey = this._effectiveItemWidth + '_' + this._effectiveItemHeight; // clear bindingContext when it is not observable because otherwise bindings to items won't reevaluate this.mMap.forEach((view, nativeView, map) => { if (!(view.bindingContext instanceof Observable)) { view.bindingContext = null; } }); // TODO: this is ugly look here: https://github.com/nativescript-vue/nativescript-vue/issues/525 // this.clearRealizedCells(); // dispatch_async(main_queue, () => { this.nativeViewProtected.reloadData(); this.nativeViewProtected.collectionViewLayout.invalidateLayout(); if (delayUpdateScrollPosition) { setTimeout(() => { this._updateScrollPosition(); }, 0); } else { this._updateScrollPosition(); } this._initAutoPlay(this.autoPlay); // }); if (this.indicator) { this.indicator.setCount(this._childrenCount); } } refreshVisibleItems() { const view = this.nativeViewProtected; if (!view) { return; } const visibles = view.indexPathsForVisibleItems; UIView.performWithoutAnimation(() => { view.performBatchUpdatesCompletion(() => { view.reloadItemsAtIndexPaths(visibles); }, null); }); } onLoaded() { super.onLoaded(); if (this._isDataDirty && this._effectiveItemWidth !== undefined && this._effectiveItemHeight !== undefined) { this.refresh(); } this.nativeViewProtected.delegate = this.mDelegate; if (!this.items && this._childrenCount > 0) { selectedIndexProperty.coerce(this); this._updateScrollPosition(); } } onUnloaded() { if (this.nativeViewProtected) { this.nativeViewProtected.delegate = null; } super.onUnloaded(); } disposeNativeView() { this.mDelegate = null; this.mDataSource = null; this.nativeViewProtected.delegate = null; this.mLayout = null; this.clearRealizedCells(); super.disposeNativeView(); } clearRealizedCells() { this.mMap.forEach((value, key) => { this._removeContainer(key); this._clearCellViews(key); }); this.mMap.clear(); } _clearCellViews(cell) { // if (cell && cell.view) { // if (cell.view.nativeViewProtected) { // cell.view.nativeViewProtected.removeFromSuperview(); // } // cell.owner = undefined; // } const view = cell.view; if (!view) { return; } // This is to clear the StackLayout that is used to wrap ProxyViewContainer instances. if (view.parent && !(view.parent instanceof Pager)) { this._removeView(view.parent); } // No need to request layout when we are removing cells. cell.owner = undefined; const preparing = this.mPreparingCell; this.mPreparingCell = true; if (view.parent && !(view.parent instanceof Pager)) { if (!(view.parent instanceof Pager)) { this._removeView(view.parent); } else { view.parent._removeView(view); } } this.mPreparingCell = preparing; this.mMap.delete(cell); } [disableSwipeProperty.setNative](value) { this.nativeViewProtected.scrollEnabled = !value; this.mDisableSwipe = value; } [contentInsetAdjustmentBehaviorProperty.setNative](value) { this.nativeViewProtected.contentInsetAdjustmentBehavior = value; } get disableAnimation() { return this.mDisableAnimation; } set disableAnimation(value) { this.mDisableAnimation = value; } _removeContainer(cell, index) { const view = cell.view; this.notify({ eventName: Pager.itemDisposingEvent, index, ios: cell, view }); if (view && view.parent) { // This is to clear the StackLayout that is used to wrap ProxyViewContainer instances. if (!(view.parent instanceof Pager)) { this._removeView(view.parent); } view.parent._removeView(view); } this.mMap.delete(cell); } // called by N when the size actually changed // _onSizeChanged() { // dispatch_async(main_queue, () => { // if (!this.pager) { // return; // } // this.pager.reloadData(); // // if (changed) { // this._updateScrollPosition(); // // } // this._initAutoPlay(this.autoPlay); // }); // } onMeasure(widthMeasureSpec, heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); this.mMap.forEach((childView, pagerCell) => { View.measureChild(this, childView, childView._currentWidthMeasureSpec, childView._currentHeightMeasureSpec); }); } onLayout(left, top, right, bottom) { super.onLayout(left, top, right, bottom); if (this.iosOverflowSafeArea) { const safeArea = this.getSafeAreaInsets(); this._effectiveItemHeight += safeArea.top + safeArea.bottom; } if (!this.nativeView) { return; } // this.nativeViewProtected.frame = this.nativeView.bounds; const layoutView = this.nativeViewProtected.collectionViewLayout; if (!layoutView) { return; } layoutView.invalidateLayout(); const size = this._getSize(); const width = Utils.layout.toDevicePixels(size.width); const height = Utils.layout.toDevicePixels(size.height); this.mMap.forEach((childView, pagerCell) => { View.layoutChild(this, childView, 0, 0, width, height); }); // there is no need to call refresh if it was triggered before with same size. // this refresh is just to handle size change const layoutKey = this._effectiveItemWidth + '_' + this._effectiveItemHeight; if (this.mLastLayoutKey !== layoutKey) { this.refresh(true); } } requestLayout() { // When preparing cell don't call super - no need to invalidate our measure when cell desiredSize is changed. if (!this.mPreparingCell) { super.requestLayout(); } } _prepareCell(cell, indexPath) { try { this.mPreparingCell = true; const index = indexPath.row; let view = cell.view; const template = this._getItemTemplate(indexPath.row); if (!view) { view = template.createView(); if (!view && this._itemViewLoader !== undefined) { view = this._itemViewLoader(this._getItemTemplateKey(indexPath.row)); } } const bindingContext = this._getDataItem(indexPath.row); const args = { eventName: Pager.itemLoadingEvent, object: this, index, android: undefined, ios: cell, view, bindingContext }; this.notify(args); view = args.view || this._getDefaultItemContent(indexPath.row); // Proxy containers should not get treated as layouts. // Wrap them in a real layout as well. if (view instanceof ProxyViewContainer) { const sp = new StackLayout(); sp.addChild(view); view = sp; } // If cell is reused it have old content - remove it first. if (!cell.view) { cell.owner = new WeakRef(view); } else if (cell.view !== view) { this.mMap.delete(cell); this._removeContainer(cell, index); cell.view.nativeViewProtected.removeFromSuperview(); cell.owner = new WeakRef(view); } if (view) { view.bindingContext = bindingContext; } this.mMap.set(cell, view); if (view && !view.parent) { this._addView(view); // prevent infinit request layout // view['performLayout'] = () => { // this._layoutCell(view, indexPath); // const size = this._getSize(); // const width = layout.toDevicePixels(size.width); // const height = layout.toDevicePixels(size.height); // if (view && view.isLayoutRequired) { // View.layoutChild(this, view, 0, 0, width, height); // } // }; if (this.iosOverflowSafeArea) { const innerView = UICellView.new(); innerView.view = new WeakRef(view); innerView.addSubview(view.nativeViewProtected); cell.contentView.addSubview(innerView); } else { cell.contentView.addSubview(view.nativeViewProtected); } } this._layoutCell(view, indexPath); } finally { this.mPreparingCell = false; } } _layoutCell(cellView, index) { if (cellView) { const size = this._getSize(); const width = Utils.layout.toDevicePixels(size.width); const height = Utils.layout.toDevicePixels(size.height); const widthMeasureSpec = Utils.layout.makeMeasureSpec(width, Utils.layout.EXACTLY); const heightMeasureSpec = Utils.layout.makeMeasureSpec(height, Utils.layout.EXACTLY); const measured = View.measureChild(this, cellView, widthMeasureSpec, heightMeasureSpec); } } get horizontalOffset() { return this.nativeViewProtected ? this.nativeViewProtected.contentOffset.x : 0; } get verticalOffset() { return this.nativeViewProtected ? this.nativeViewProtected.contentOffset.y : 0; } _getSpacing() { return Utils.layout.toDeviceIndependentPixels(this.convertToSize(this.spacing)); } _getPeaking() { return Utils.layout.toDeviceIndependentPixels(this.convertToSize(this.peaking)); } _getSize() { let width = Utils.layout.toDeviceIndependentPixels(this._effectiveItemWidth); let height = Utils.layout.toDeviceIndependentPixels(this._effectiveItemHeight); if (this.orientation === 'vertical') { height = (height - (this._getSpacing() * 2 + this._getPeaking() * 2)) / this.perPage; } else { width = (width - (this._getSpacing() * 2 + this._getPeaking() * 2)) / this.perPage; } if (Number.isNaN(width)) { width = 0; } if (Number.isNaN(height)) { height = 0; } return { width, height }; } } __decorate([ profile ], Pager.prototype, "refresh", null); var PagerCell = /** @class */ (function (_super) { __extends(PagerCell, _super); function PagerCell() { return _super !== null && _super.apply(this, arguments) || this; } Object.defineProperty(PagerCell.prototype, "view", { get: function () { return this.owner ? this.owner.get() : null; }, enumerable: true, configurable: true }); PagerCell.initWithEmptyBackground = function () { var cell = PagerCell.new(); // Clear background by default - this will make cells transparent cell.backgroundColor = null; return cell; }; PagerCell.prototype.willMoveToSuperview = function (newSuperview) { var parent = (this.view ? this.view.parent : null); // When inside Pager and there is no newSuperview this cell is // removed from native visual tree so we remove it from our tree too. if (parent && !newSuperview) { parent._removeContainer(this, this.index); } }; return PagerCell; }(UICollectionViewCell)); var UICollectionDelegateImpl = /** @class */ (function (_super) { __extends(UICollectionDelegateImpl, _super); function UICollectionDelegateImpl() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.isScrolling = false; return _this; } UICollectionDelegateImpl_1 = UICollectionDelegateImpl; UICollectionDelegateImpl.initWithOwner = function (owner) { var delegate = UICollectionDelegateImpl_1.alloc().init(); delegate._owner = owner; return delegate; }; UICollectionDelegateImpl.prototype.collectionViewLayoutInsetForSectionAtIndex = function (collectionView, collectionViewLayout, section) { var owner = this._owner ? this._owner.get() : null; if (owner) { var inset = owner._getSpacing() + owner._getPeaking(); if (owner.orientation === 'vertical') { return new UIEdgeInsets({ bottom: inset, left: 0, right: 0, top: inset }); } return new UIEdgeInsets({ bottom: 0, left: inset, right: inset, top: 0 }); } return new UIEdgeInsets({ bottom: 0, left: 0, right: 0, top: 0 }); }; UICollectionDelegateImpl.prototype.collectionViewLayoutSizeForItemAtIndexPath = function (collectionView, collectionViewLayout, indexPath) { var owner = this._owner && this._owner.get(); if (!owner) return CGSizeZero; var size = owner._getSize(); return CGSizeMake(size.width, size.height); }; UICollectionDelegateImpl.prototype.collectionViewWillDisplayCellForItemAtIndexPath = function (collectionView, cell, indexPath) { var owner = this._owner && this._owner.get(); if (owner) { if (!owner.mIsInit) { owner._updateScrollPosition(); collectionView.collectionViewLayout.invalidateLayout(); owner.mIsInit = true; } if (owner.items && indexPath.row === owner.lastIndex - owner.loadMoreCount) { owner.notify({ eventName: Pager.loadMoreItemsEvent, object: owner }); } } if (cell.preservesSuperviewLayoutMargins) { cell.preservesSuperviewLayoutMargins = false; } if (cell.layoutMargins) { cell.layoutMargins = UIEdgeInsetsZero; } }; UICollectionDelegateImpl.prototype.collectionViewLayoutMinimumLineSpacingForSectionAtIndex = function (collectionView, collectionViewLayout, section) { var _a; var owner = this._owner ? this._owner.get() : null; return (_a = owner === null || owner === void 0 ? void 0 : owner._getSpacing()) !== null && _a !== void 0 ? _a : 0; }; UICollectionDelegateImpl.prototype.scrollViewWillBeginDragging = function (scrollView) { var owner = this._owner && this._owner.get(); if (owner) { if (owner.lastEvent === 0) { owner.notify({ eventName: Pager.swipeStartEvent, object: owner }); owner.lastEvent = 1; } } }; UICollectionDelegateImpl.prototype.scrollViewDidEndScrollingAnimation = function (scrollView) { var owner = this._owner ? this._owner.get() : null; if (owner) { owner.notify({ eventName: Pager.swipeEvent, object: owner }); } }; UICollectionDelegateImpl.prototype.scrollViewDidScroll = function (scrollView) { var owner = this._owner.get(); if (owner) { var width = void 0; var offset = void 0; var size = owner._getRealWidthHeight(); var total = void 0; if (owner.orientation === 'vertical') { width = size.height; offset = scrollView.contentOffset.y; total = scrollView.contentSize.height - scrollView.bounds.size.height; } else { width = size.width; offset = scrollView.contentOffset.x; total = scrollView.contentSize.width - scrollView.bounds.size.width; } var percent = offset / total; var progress = percent * (owner.itemCount - 1); // if (owner.indicatorView && owner.indicatorView.setWithProgressAnimated && !Number.isNaN(progress)) { // owner.indicatorView.progress = progress; // } var index = parseInt(progress.toFixed(0), 10); if (owner.indicator && !Number.isNaN(index)) { if (!(owner.circularMode && (index === 0 || index === owner.firstDummy))) { owner.indicator.setSelection(owner.getPosition(index)); } } owner.notify({ object: owner, eventName: Pager.scrollEvent, selectedIndex: Math.floor(progress), currentPosition: progress, scrollX: owner.horizontalOffset, scrollY: owner.verticalOffset }); if (owner.lastEvent === 1) { owner.notify({ eventName: Pager.swipeOverEvent, object: owner }); owner.lastEvent = 1; } // (scrollView as any).scrollToItemAtIndexPathAtScrollPositionAnimated( // NSIndexPath.indexPathForRowInSection(Math.round(width),0), UICollectionViewScrollPosition.CenteredHorizontally, true // ); if (owner.circularMode) { if (!this.isScrolling) { this.isScrolling = true; var contentOffset = scrollView.contentOffset; var contentSize = scrollView.contentSize; var frameSize = scrollView.frame.size; if (contentOffset.x <= 0) { scrollView.contentOffset = CGPointMake(contentSize.width - frameSize.width * 2 + 2 * owner._getPeaking(), 0); if (owner.indicator) { owner.indicator.setSelection(owner.lastIndex, false); } } else if (contentOffset.x + frameSize.width >= contentSize.width) { scrollView.contentOffset = CGPointMake(frameSize.width - 2 * owner._getPeaking(), 0); if (owner.indicator) { owner.indicator.setSelection(0, false); } } this.isScrolling = false; } } /* if (!Number.isNaN(width)) { let page = Math.ceil(width); const doScroll = () => { if (!Number.isNaN(width)) { // scrollView.setContentOffsetAnimated(point, false); scrollView.contentOffset = CGPointMake(Math.ceil(w) * page, scrollView.contentOffset.y); } }; if (page === 0) { page = owner.itemCount - 2; doScroll(); // selectedIndexProperty.nativeValueChange(owner, owner.itemCount - 3); } else if (page === owner.itemCount) { page = 1; doScroll(); // selectedIndexProperty.nativeValueChange(owner, 0); } else { if (page === owner._childrenCount + 1) { // selectedIndexProperty.nativeValueChange(owner, 0); } else { // selectedIndexProperty.nativeValueChange(owner, page - 1); } } } */ /* if(owner){ let width = 0; let w = (layout.toDeviceIndependentPixels(owner._effectiveItemWidth) - (((owner.perPage * 2) * owner._getSpacing()) + (owner._getPeaking() * 2))) / owner.perPage; let h = (layout.toDeviceIndependentPixels(owner._effectiveItemHeight) - (((owner.perPage * 2) * owner._getSpacing()) + (owner._getPeaking() * 2))) / owner.perPage; width = scrollView.contentOffset.x / w; if (!Number.isNaN(width)) { let page = Math.ceil(width); const doScroll = () => { if (!Number.isNaN(width)) { const point = CGPointMake(Math.ceil(w) * page, scrollView.contentOffset.y); scrollView.setContentOffsetAnimated(point, false); } }; if (page === 0) { page = owner.itemCount - 2; doScroll(); selectedIndexProperty.nativeValueChange(owner, owner.itemCount - 3); } else if (page === owner.itemCount -1) { page = 1; doScroll(); selectedIndexProperty.nativeValueChange(owner, 0); } else { if(page === owner.itemCount + 1){ selectedIndexProperty.nativeValueChange(owner, 0); }else { selectedIndexProperty.nativeValueChange(owner, page - 1); } } } } */ // scrollView.setContentOffsetAnimated(CGPointMake((w * width) + 1, 0),false); // (owner.nativeView as UICollectionView).setContentOffsetAnimated(CGPointMake((w * width) + 1, 0),false); } }; UICollectionDelegateImpl.prototype.scrollViewDidEndDraggingWillDecelerate = function (scrollView, decelerate) { }; UICollectionDelegateImpl.prototype.scrollViewWillEndDraggingWithVelocityTargetContentOffset = function (scrollView, velocity, targetContentOffset) { var owner = this._owner ? this._owner.get() : null; if (!owner) return; if (owner.lastEvent === 1) { owner.notify({ eventName: Pager.swipeEndEvent, object: owner }); owner.lastEvent = 0; } }; var UICollectionDelegateImpl_1; UICollectionDelegateImpl = UICollectionDelegateImpl_1 = __decorate([ ObjCClass(UICollectionViewDelegate, UICollectionViewDelegateFlowLayout) ], UICollectionDelegateImpl); return UICollectionDelegateImpl; }(NSObject)); var UICollectionViewDataSourceImpl = /** @class */ (function (_super) { __extends(UICollectionViewDataSourceImpl, _super); function UICollectionViewDataSourceImpl() { return _super !== null && _super.apply(this, arguments) || this; } UICollectionViewDataSourceImpl_1 = UICollectionViewDataSourceImpl; UICollectionViewDataSourceImpl.initWithOwner = function (owner) { var delegate = UICollectionViewDataSourceImpl_1.alloc().init(); delegate._owner = owner; return delegate; }; UICollectionViewDataSourceImpl.prototype.collectionViewCellForItemAtIndexPath = function (collectionView, indexPath) { var owner = this._owner ? this._owner.get() : null; var cell; var count = 0; if (owner) { count = owner._childrenCount; if (owner.circularMode) { count = owner.itemCount; switch (indexPath.row) { case 0: indexPath = NSIndexPath.indexPathForRowInSection(owner.lastDummy, 0); break; case owner.firstDummy: indexPath = NSIndexPath.indexPathForRowInSection(0, 0); break; default: indexPath = NSIndexPath.indexPathForRowInSection(indexPath.row - 1, 0); break; } } } if (owner && !owner.items && count > 0) { var index = indexPath.row; var data = owner._childrenViews[index]; var viewType = data.type; owner.mPreparingCell = true; collectionView.registerClassForCellWithReuseIdentifier(PagerCell.class(), "static-".concat(viewType)); cell = collectionView.dequeueReusableCellWithReuseIdentifierForIndexPath("static-".concat(viewType), indexPath) || PagerCell.initWithEmptyBackground(); cell.index = index; var view = data.view; // if (view instanceof ProxyViewContainer) { // let sp = new StackLayout(); // sp.addChild(view); // view = sp; // } // If cell is reused it has old content - remove it first. var firstRender_1 = !cell.view; if (!cell.view) { cell.owner = new WeakRef(view); } else if (cell.view !== view) { owner._removeView(view); // (cell.view.nativeViewProtected as UIView).removeFromSuperview(); cell.owner = new WeakRef(view); } if (view && !view.parent) { // view['performLayout'] = () => { // View.measureChild( // owner, // view, // view._currentWidthMeasureSpec, // view._currentHeightMeasureSpec // ); // if (view && view.isLayoutRequired) { // View.layoutChild(owner, view, 0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); // } // }; owner._addView(view); // if (owner.iosOverflowSafeArea) { var innerView = UICellView.new(); innerView.view = new WeakRef(view); innerView.addSubview(view.nativeViewProtected); cell.contentView.addSubview(innerView); owner.mMap.set(cell, view); // } else { // cell.contentView.addSubview(view.nativeViewProtected); // } } if (firstRender_1) { view['iosIgnoreSafeArea'] = true; } owner._layoutCell(view, indexPath); var size = owner._getSize(); var width = Utils.layout.toDevicePixels(size.width); var height = Utils.layout.toDevicePixels(size.height); if (view && view.isLayoutRequired) { View.layoutChild(owner, view, 0, 0, width, height); } owner.mPreparingCell = false; return cell; } var template = owner && owner._getItemTemplate(indexPath.row); cell = collectionView.dequeueReusableCellWithReuseIdentifierForIndexPath(template.key, indexPath) || PagerCell.initWithEmptyBackground(); cell.index = indexPath; var firstRender = !cell.view; if (owner) { var size = owner._getSize(); owner._prepareCell(cell, indexPath); var cellView = cell.view; if (firstRender) { cellView['iosIgnoreSafeArea'] = true; } if (cellView && cellView.isLayoutRequired) { View.layoutChild(owner, cellView, 0, 0, Utils.layout.toDevicePixels(size.width), Utils.layout.toDevicePixels(size.height)); } } return cell; }; UICollectionViewDataSourceImpl.prototype.collectionViewNumberOfItemsInSection = function (collectionView, section) { var owner = this._owner ? this._owner.get() : null; // make sure we dont start to load static view if the pager is not loaded. // otherwise static items wont "load" if (!owner || !owner.isLoaded) return 0; return owner.circularMode ? owner.itemCount : owner._childrenCount; }; UICollectionViewDataSourceImpl.prototype.numberOfSectionsInCollectionView = function (collectionView) { return 1; }; var UICollectionViewDataSourceImpl_1; UICollectionViewDataSourceImpl = UICollectionViewDataSourceImpl_1 = __decorate([ ObjCClass(UICollectionViewDataSource) ], UICollectionViewDataSourceImpl); return UICollectionViewDataSourceImpl; }(NSObject)); var UICollectionViewFlowLinearLayoutImpl = /** @class */ (function (_super) { __extends(UICollectionViewFlowLinearLayoutImpl, _super); function UICollectionViewFlowLinearLayoutImpl() { return _super !== null && _super.apply(this, arguments) || this; } UICollectionViewFlowLinearLayoutImpl.initWithOwner = function (owner) { var layout = UICollectionViewFlowLinearLayoutImpl.new(); layout._owner = owner; layout._curl = CATransition.animation(); return layout; }; UICollectionViewFlowLinearLayoutImpl.prototype.layoutAttributesForElementsInRect = function (rect) { var owner = this._owner ? this._owner.get() : null; var originalLayoutAttribute = _super.prototype.layoutAttributesForElementsInRect.call(this, rect); var visibleLayoutAttributes = NSMutableArray.alloc().init(); if (owner === null || owner === void 0 ? void 0 : owner.transformers) { var transformsArray = owner.transformers .split(' ') .map(function (s) { return Pager.mRegisteredTransformers[s]; }) .filter(function (s) { return !!s; }); if (transformsArray.length) { var collectionView = this.collectionView; var count = originalLayoutAttribute.count; for (var i = 0; i < count; i++) { var attributes = originalLayoutAttribute.objectAtIndex(i); visibleLayoutAttributes.addObject(attributes); for (var _i = 0, transformsArray_1 = transformsArray; _i < transformsArray_1.length; _i++) { var transformer = transformsArray_1[_i]; transformer(i, attributes, owner, collectionView); } } } return visibleLayoutAttributes; } return originalLayoutAttribute; }; UICollectionViewFlowLinearLayoutImpl.prototype.shouldInvalidateLayoutForBoundsChange = function (newBounds) { return true; }; UICollectionViewFlowLinearLayoutImpl.prototype.initialLayoutAttributesForAppearingItemAtIndexPath = function (itemIndexPath) { var attrs = _super.prototype.initialLayoutAttributesForAppearingItemAtIndexPath.call(this, itemIndexPath); attrs.alpha = 1; return attrs; }; UICollectionViewFlowLinearLayoutImpl.prototype.finalLayoutAttributesForDisappearingItemAtIndexPath = function (itemIndexPath) { var attrs = _super.prototype.finalLayoutAttributesForDisappearingItemAtIndexPath.call(this, itemIndexPath); attrs.alpha = 1; return attrs; }; UICollectionViewFlowLinearLayoutImpl.prototype.targetCon