From 2ccfb36ca70062e9c04b7ed238413ba9e08d99fa Mon Sep 17 00:00:00 2001 From: Martin Yankov Date: Thu, 9 Aug 2018 15:28:34 +0300 Subject: [PATCH] refactor safe area application code --- tns-core-modules/ui/core/view/view-common.ts | 14 +- tns-core-modules/ui/core/view/view.android.ts | 6 +- tns-core-modules/ui/core/view/view.d.ts | 29 ++- tns-core-modules/ui/core/view/view.ios.ts | 239 +++++++++--------- .../ui/layouts/grid-layout/grid-layout.ios.ts | 4 +- .../ui/layouts/layout-base.ios.ts | 76 ------ .../layouts/stack-layout/stack-layout.ios.ts | 5 +- .../ui/layouts/wrap-layout/wrap-layout.ios.ts | 3 +- .../ui/list-view/list-view-common.ts | 4 +- .../ui/list-view/list-view.ios.ts | 75 ------ .../ui/scroll-view/scroll-view.ios.ts | 113 +-------- 11 files changed, 175 insertions(+), 393 deletions(-) diff --git a/tns-core-modules/ui/core/view/view-common.ts b/tns-core-modules/ui/core/view/view-common.ts index bd90a7fb1..91a1fd4ad 100644 --- a/tns-core-modules/ui/core/view/view-common.ts +++ b/tns-core-modules/ui/core/view/view-common.ts @@ -641,7 +641,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { } public abstract onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void; - public abstract onLayout(left: number, top: number, right: number, bottom: number, insets?: {left, top, right, bottom}): void; + public abstract onLayout(left: number, top: number, right: number, bottom: number): void; public abstract layoutNativeView(left: number, top: number, right: number, bottom: number): void; public static resolveSizeAndState(size: number, specSize: number, specMode: number, childMeasuredState: number): number { @@ -879,6 +879,18 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { return undefined; } + public getSafeAreaInsets(): { left, top, right, bottom } { + return undefined; + } + + public getPositionFromFrame(frame: CGRect): { left, top, right, bottom } { + return undefined; + } + + public getFrameFromPosition(position: { left, top, right, bottom }, insets?: { left, top }): CGRect { + return undefined; + } + public getFullscreenArea(): any { return undefined; } diff --git a/tns-core-modules/ui/core/view/view.android.ts b/tns-core-modules/ui/core/view/view.android.ts index 22f847d59..348bc9595 100644 --- a/tns-core-modules/ui/core/view/view.android.ts +++ b/tns-core-modules/ui/core/view/view.android.ts @@ -804,7 +804,11 @@ export class View extends ViewCommon { } } -export class CustomLayoutView extends View implements CustomLayoutViewDefinition { +export class ContainerView extends View { + // +} + +export class CustomLayoutView extends ContainerView implements CustomLayoutViewDefinition { nativeViewProtected: android.view.ViewGroup; public createNativeView() { diff --git a/tns-core-modules/ui/core/view/view.d.ts b/tns-core-modules/ui/core/view/view.d.ts index 1d1417f49..c540ba8c0 100644 --- a/tns-core-modules/ui/core/view/view.d.ts +++ b/tns-core-modules/ui/core/view/view.d.ts @@ -404,7 +404,7 @@ export abstract class View extends ViewBase { * @param right Right position, relative to parent * @param bottom Bottom position, relative to parent */ - public onLayout(left: number, top: number, right: number, bottom: number, insets?: {left, top, right, bottom}): void; + public onLayout(left: number, top: number, right: number, bottom: number): void; /** * This method must be called by onMeasure(int, int) to store the measured width and measured height. Failing to do so will trigger an exception at measurement time. @@ -415,7 +415,6 @@ export abstract class View extends ViewBase { /** * Called from onLayout when native view position is about to be changed. - * @param parent This parameter is not used. You can pass null. * @param left Left position, relative to parent * @param top Top position, relative to parent * @param right Right position, relative to parent @@ -427,7 +426,7 @@ export abstract class View extends ViewBase { * Measure a child by taking into account its margins and a given measureSpecs. * @param parent This parameter is not used. You can pass null. * @param child The view to be measured. - * @param measuredWidth The measured width that the parent layout specifies for this view. + * @param measuredWidth The measured width that the parent layout specifies for this view. * @param measuredHeight The measured height that the parent layout specifies for this view. */ public static measureChild(parent: View, child: View, widthMeasureSpec: number, heightMeasureSpec: number): { measuredWidth: number; measuredHeight: number }; @@ -527,6 +526,21 @@ export abstract class View extends ViewBase { */ public createAnimation(options: AnimationDefinition): Animation; + /** + * Returns the iOS safe area insets of this view. + */ + public getSafeAreaInsets(): { left, top, right, bottom }; + + /** + * Transforms iOS CGRect to a position object with left, top, right and bottom. + */ + public getPositionFromFrame(frame: any): { left, top, right, bottom }; + + /** + * Transforms a position object with left, top, right and bottom to an iOS CGRect. + */ + public getFrameFromPosition(position: { left, top, right, bottom }, insets?: { left, top }): any; + /** * Returns the iOS safe area frame of the closest parent with UIViewController. */ @@ -706,10 +720,17 @@ export abstract class View extends ViewBase { _setValue(property: any, value: any): never; } +/** + * Base class for all UI components that are containers. + */ +export class ContainerView extends View { + +} + /** * Base class for all UI components that implement custom layouts. */ -export class CustomLayoutView extends View { +export class CustomLayoutView extends ContainerView { //@private /** * @private diff --git a/tns-core-modules/ui/core/view/view.ios.ts b/tns-core-modules/ui/core/view/view.ios.ts index 9cb217da7..79ef70942 100644 --- a/tns-core-modules/ui/core/view/view.ios.ts +++ b/tns-core-modules/ui/core/view/view.ios.ts @@ -87,22 +87,18 @@ export class View extends ViewCommon { @profile public layout(left: number, top: number, right: number, bottom: number, setFrame = true): void { const { boundsChanged, sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom); - let actualPosition = {left, top, right, bottom}; if (setFrame) { - actualPosition = this.layoutNativeView(left, top, right, bottom) || actualPosition; + this.layoutNativeView(left, top, right, bottom); } if (boundsChanged || (this._privateFlags & PFLAG_LAYOUT_REQUIRED) === PFLAG_LAYOUT_REQUIRED) { - let insets = { left: 0, top: 0, right: 0, bottom: 0}; - - if (majorVersion > 10) { - insets.left = layout.toDevicePixels(this.nativeViewProtected.safeAreaInsets.left); - insets.top = layout.toDevicePixels(this.nativeViewProtected.safeAreaInsets.top); - insets.right = layout.toDevicePixels(this.nativeViewProtected.safeAreaInsets.right); - insets.bottom = layout.toDevicePixels(this.nativeViewProtected.safeAreaInsets.bottom); + let position = { left, top, right, bottom }; + if (this.nativeViewProtected) { + const frame = this.nativeViewProtected.frame; + position = this.getPositionFromFrame(frame); } - this.onLayout(actualPosition.left, actualPosition.top, actualPosition.right, actualPosition.bottom, insets); + this.onLayout(position.left, position.top, position.right, position.bottom); this._privateFlags &= ~PFLAG_LAYOUT_REQUIRED; } @@ -150,11 +146,11 @@ export class View extends ViewCommon { this.setMeasuredDimension(widthAndState, heightAndState); } - public onLayout(left: number, top: number, right: number, bottom: number, insets?: {left, top, right, bottom}): void { - // + public onLayout(left: number, top: number, right: number, bottom: number): void { + // } - public _setNativeViewFrame(nativeView: UIView, frame: CGRect): CGRect { + public _setNativeViewFrame(nativeView: UIView, frame: CGRect): void { if (!CGRectEqualToRect(nativeView.frame, frame)) { if (traceEnabled()) { traceWrite(this + ", Native setFrame: = " + NSStringFromCGRect(frame), traceCategories.Layout); @@ -166,34 +162,18 @@ export class View extends ViewCommon { nativeView.transform = CGAffineTransformIdentity; nativeView.frame = frame; nativeView.transform = transform; - } - else { + } else { nativeView.frame = frame; } - if (nativeView.safeAreaInsets) { - const leftInset = layout.toDevicePixels(nativeView.safeAreaInsets.left); - const topInset = layout.toDevicePixels(nativeView.safeAreaInsets.top); + const adjustedFrame = this.applySafeAreaInsets(frame); + if (adjustedFrame) { + nativeView.frame = adjustedFrame; + } - const left = layout.toDevicePixels(frame.origin.x); - const top = layout.toDevicePixels(frame.origin.y); - const right = layout.toDevicePixels(frame.origin.x + frame.size.width); - const bottom = layout.toDevicePixels(frame.origin.y + frame.size.height); - if (leftInset || topInset) { - const frameNew = CGRectMake(layout.toDeviceIndependentPixels(left + leftInset), layout.toDeviceIndependentPixels(top + topInset), layout.toDeviceIndependentPixels(right - left), layout.toDeviceIndependentPixels(bottom - top)); - nativeView.frame = frameNew; - const boundsOrigin = nativeView.bounds.origin; - nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, frameNew.size.width, frameNew.size.height); - } - else { - const boundsOrigin = nativeView.bounds.origin; - nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, frame.size.width, frame.size.height); - } - } - else { - const boundsOrigin = nativeView.bounds.origin; - nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, frame.size.width, frame.size.height); - } + const boundsOrigin = nativeView.bounds.origin; + const boundsFrame = nativeView.frame; + nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, boundsFrame.size.width, boundsFrame.size.height); this._raiseLayoutChangedEvent(); this._isLaidOut = true; @@ -201,25 +181,16 @@ export class View extends ViewCommon { // Rects could be equal on the first layout and an event should be raised. this._raiseLayoutChangedEvent(); } - - return nativeView.frame; } - public layoutNativeView(left: number, top: number, right: number, bottom: number): any { + public layoutNativeView(left: number, top: number, right: number, bottom: number): void { if (!this.nativeViewProtected) { return; } const nativeView = this.nativeViewProtected; - const frame = CGRectMake(layout.toDeviceIndependentPixels(left), layout.toDeviceIndependentPixels(top), layout.toDeviceIndependentPixels(right - left), layout.toDeviceIndependentPixels(bottom - top)); - const actualFrame = this._setNativeViewFrame(nativeView, frame) || frame; - - const actualLeft = Math.round(layout.toDevicePixels(actualFrame.origin.x)); - const actualTop = Math.round(layout.toDevicePixels(actualFrame.origin.y)); - const actualRight = Math.round(layout.toDevicePixels(actualFrame.origin.x + actualFrame.size.width)); - const actualBottom = Math.round(layout.toDevicePixels(actualFrame.origin.y + actualFrame.size.height)); - - return { left: actualLeft, top: actualTop, right: actualRight, bottom: actualBottom}; + const frame = this.getFrameFromPosition({ left, top, right, bottom }); + this._setNativeViewFrame(nativeView, frame); } public _setLayoutFlags(left: number, top: number, right: number, bottom: number): void { @@ -246,6 +217,54 @@ export class View extends ViewCommon { return false; } + protected applySafeAreaInsets(frame: CGRect): CGRect { + if (majorVersion > 10) { + const insets = this.getSafeAreaInsets(); + + if (insets.left || insets.top) { + const position = this.getPositionFromFrame(frame); + const adjustedFrame = this.getFrameFromPosition(position, insets); + return adjustedFrame; + } + } + + return null; + } + + public getSafeAreaInsets(): { left, top, right, bottom } { + const safeAreaInsets = this.nativeViewProtected && this.nativeViewProtected.safeAreaInsets; + let insets = { left: 0, top: 0, right: 0, bottom: 0 }; + + if (safeAreaInsets) { + insets.left = layout.round(layout.toDevicePixels(safeAreaInsets.left)); + insets.top = layout.round(layout.toDevicePixels(safeAreaInsets.top)); + insets.right = layout.round(layout.toDevicePixels(safeAreaInsets.right)); + insets.bottom = layout.round(layout.toDevicePixels(safeAreaInsets.bottom)); + } + + return insets; + } + + public getPositionFromFrame(frame: CGRect): { left, top, right, bottom } { + const left = layout.round(layout.toDevicePixels(frame.origin.x)); + const top = layout.round(layout.toDevicePixels(frame.origin.y)); + const right = layout.round(layout.toDevicePixels(frame.origin.x + frame.size.width)); + const bottom = layout.round(layout.toDevicePixels(frame.origin.y + frame.size.height)); + + return { left, right, top, bottom }; + } + + public getFrameFromPosition(position: { left, top, right, bottom }, insets?: { left, top }): CGRect { + insets = insets || { left: 0, top: 0 }; + + const left = layout.round(layout.toDeviceIndependentPixels(position.left + insets.left)); + const top = layout.round(layout.toDeviceIndependentPixels(position.top + insets.top)); + const width = layout.round(layout.toDeviceIndependentPixels(position.right - position.left)); + const height = layout.round(layout.toDeviceIndependentPixels(position.bottom - position.top)); + + return CGRectMake(left, top, width, height); + } + public getFullscreenArea(): any { const parentWithController = ios.getParentWithViewController(this); return parentWithController.viewController.view.frame; @@ -419,7 +438,7 @@ export class View extends ViewCommon { protected _hideNativeModalView(parent: View) { if (!parent || !parent.viewController) { traceError("Trying to hide modal view but no parent with viewController specified.") - return; + return; } const parentController = parent.viewController; @@ -585,7 +604,49 @@ export class View extends ViewCommon { } View.prototype._nativeBackgroundState = "unset"; -export class CustomLayoutView extends View { +export class ContainerView extends View { + protected applySafeAreaInsets(frame: CGRect): CGRect { + if (majorVersion > 10) { + const locationOnScreen = this.getLocationOnScreen(); + + if (locationOnScreen) { + const safeArea = this.getSafeArea(); + const fullscreen = this.getFullscreenArea(); + const onScreenLeft = layout.round(layout.toDevicePixels(locationOnScreen.x)); + const onScreenTop = layout.round(layout.toDevicePixels(locationOnScreen.y)); + + const position = this.getPositionFromFrame(frame); + const safeAreaPosition = this.getPositionFromFrame(safeArea); + const fullscreenPosition = this.getPositionFromFrame(fullscreen); + + const adjustedPosition = position; + + if (position.left && onScreenLeft <= safeAreaPosition.left) { + adjustedPosition.left = fullscreenPosition.left; + } + + if (position.top && onScreenTop <= safeAreaPosition.top) { + adjustedPosition.top = fullscreenPosition.top; + } + + if (position.right < fullscreenPosition.right && position.right >= safeAreaPosition.right) { + adjustedPosition.right = fullscreenPosition.right; + } + + if (position.bottom < fullscreenPosition.bottom && position.bottom >= safeAreaPosition.bottom) { + adjustedPosition.bottom = fullscreenPosition.bottom; + } + + const adjustedFrame = CGRectMake(layout.toDeviceIndependentPixels(adjustedPosition.left), layout.toDeviceIndependentPixels(adjustedPosition.top), layout.toDeviceIndependentPixels(adjustedPosition.right - adjustedPosition.left), layout.toDeviceIndependentPixels(adjustedPosition.bottom - adjustedPosition.top)); + return adjustedFrame; + } + } + + return null; + } +} + +export class CustomLayoutView extends ContainerView { nativeViewProtected: UIView; @@ -683,8 +744,7 @@ export namespace ios { } export function updateConstraints(controller: UIViewController, owner: View): void { - const root = controller.view; - if (!root.safeAreaLayoutGuide) { + if (majorVersion <= 10) { const layoutGuide = initLayoutGuide(controller); (controller.view).safeAreaLayoutGuide = layoutGuide; } @@ -703,27 +763,7 @@ export namespace ios { return layoutGuide; } - function getStatusBarHeight(viewController?: UIViewController): number { - const app = iosUtils.getter(UIApplication, UIApplication.sharedApplication); - if (!app || app.statusBarHidden) { - return 0; - } - - if (viewController && viewController.prefersStatusBarHidden) { - return 0; - } - - const statusFrame = app.statusBarFrame; - return Math.min(statusFrame.size.width, statusFrame.size.height); - } - export function layoutView(controller: UIViewController, owner: View): void { - let left: number, top: number, width: number, height: number; - - const frame = controller.view.frame; - const fullscreenOrigin = frame.origin; - const fullscreenSize = frame.size; - let layoutGuide = controller.view.safeAreaLayoutGuide; if (!layoutGuide) { traceWrite(`safeAreaLayoutGuide during layout of ${owner}. Creating fallback constraints, but layout might be wrong.`, @@ -732,62 +772,17 @@ export namespace ios { layoutGuide = initLayoutGuide(controller); } const safeArea = layoutGuide.layoutFrame; - const safeOrigin = safeArea.origin; + const position = owner.getPositionFromFrame(safeArea); const safeAreaSize = safeArea.size; - const navController = controller.navigationController; - const navBarHidden = navController ? navController.navigationBarHidden : true; - const scrollable = isContentScrollable(controller, owner); - const hasChildControllers = controller.childViewControllers.count > 0; - - if (!(controller.edgesForExtendedLayout & UIRectEdge.Top)) { - const statusBarHeight = getStatusBarHeight(controller); - const navBarHeight = controller.navigationController ? controller.navigationController.navigationBar.frame.size.height : 0; - fullscreenOrigin.y = safeOrigin.y; - fullscreenSize.height -= (statusBarHeight + navBarHeight); - } - - left = safeOrigin.x; - width = safeAreaSize.width; - top = safeOrigin.y; - height = safeAreaSize.height; - - // left = fullscreenOrigin.x; - // width = fullscreenSize.width; - // top = fullscreenOrigin.y; - // height = fullscreenSize.height; - - // if (hasChildControllers) { - // // If not inner most extend to fullscreen - // top = fullscreenOrigin.y; - // height = fullscreenSize.height; - // } else if (!scrollable) { - // // If not scrollable dock under safe area - // top = safeOrigin.y; - // height = safeAreaSize.height; - // } else if (navBarHidden) { - // // If scrollable but no navigation bar dock under safe area - // top = safeOrigin.y; - // height = navController ? (fullscreenSize.height - top) : safeAreaSize.height; - // } else { - // // If scrollable and navigation bar extend to fullscreen - // top = fullscreenOrigin.y; - // height = fullscreenSize.height; - // } - - left = layout.toDevicePixels(left); - top = layout.toDevicePixels(top); - width = layout.toDevicePixels(width); - height = layout.toDevicePixels(height); - - const safeAreaWidth = layout.toDevicePixels(safeAreaSize.width); - const safeAreaHeight = layout.toDevicePixels(safeAreaSize.height); + const safeAreaWidth = layout.round(layout.toDevicePixels(safeAreaSize.width)); + const safeAreaHeight = layout.round(layout.toDevicePixels(safeAreaSize.height)); const widthSpec = layout.makeMeasureSpec(safeAreaWidth, layout.EXACTLY); const heightSpec = layout.makeMeasureSpec(safeAreaHeight, layout.EXACTLY); View.measureChild(null, owner, widthSpec, heightSpec); - View.layoutChild(null, owner, left, top, width + left, height + top); + View.layoutChild(null, owner, position.left, position.top, position.right, position.bottom); layoutParent(owner.parent); } diff --git a/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts b/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts index cbf91902c..6d2b153b8 100644 --- a/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts +++ b/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts @@ -156,9 +156,11 @@ export class GridLayout extends GridLayoutBase { this.setMeasuredDimension(widthSizeAndState, heightSizeAndState); } - public onLayout(left: number, top: number, right: number, bottom: number, insets: {left, top, right, bottom}): void { + public onLayout(left: number, top: number, right: number, bottom: number): void { super.onLayout(left, top, right, bottom); + const insets = this.getSafeAreaInsets(); + let paddingLeft = this.effectiveBorderLeftWidth + this.effectivePaddingLeft + insets.left; let paddingTop = this.effectiveBorderTopWidth + this.effectivePaddingTop + insets.top; diff --git a/tns-core-modules/ui/layouts/layout-base.ios.ts b/tns-core-modules/ui/layouts/layout-base.ios.ts index 3bb02a952..61a09df2a 100644 --- a/tns-core-modules/ui/layouts/layout-base.ios.ts +++ b/tns-core-modules/ui/layouts/layout-base.ios.ts @@ -31,82 +31,6 @@ export class LayoutBase extends LayoutBaseCommon { } } - public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { - // if (!CGRectEqualToRect(nativeView.frame, frame)) { - // if (traceEnabled()) { - // traceWrite(this + ", Native setFrame: = " + NSStringFromCGRect(frame), traceCategories.Layout); - // } - // this._cachedFrame = frame; - // if (this._hasTransfrom) { - // // Always set identity transform before setting frame; - // const transform = nativeView.transform; - // nativeView.transform = CGAffineTransformIdentity; - // nativeView.frame = frame; - // nativeView.transform = transform; - // } - // else { - // nativeView.frame = frame; - // } - - nativeView.frame = frame; - const locationOnScreen = this.getLocationInWindow(); - - if (locationOnScreen) { - - const safeArea = this.getSafeArea(); - const fullscreen = this.getFullscreenArea(); - const onScreenLeft = layout.toDevicePixels(layout.round(locationOnScreen.x)); - const onScreenTop = layout.toDevicePixels(layout.round(locationOnScreen.y)); - - let left = layout.toDevicePixels(frame.origin.x); - let top = layout.toDevicePixels(frame.origin.y); - let width = layout.toDevicePixels(frame.size.width); - let height = layout.toDevicePixels(frame.size.height); - - if (majorVersion > 10) { - let newLeft = left; - let newTop = top; - let newWidth = width; - let newHeight = height; - - if (left !== 0 && onScreenLeft <= layout.toDevicePixels(safeArea.origin.x)) { - newLeft = layout.toDevicePixels(fullscreen.origin.x); - newWidth = width + onScreenLeft; - } - - if (top !== 0 && onScreenTop <= layout.toDevicePixels(safeArea.origin.y)) { - newTop = layout.toDevicePixels(fullscreen.origin.y); - newHeight = height + onScreenTop; - } - - if (width && width < layout.toDevicePixels(fullscreen.size.width) && onScreenLeft + width >= layout.toDevicePixels(safeArea.origin.x) + layout.toDevicePixels(safeArea.size.width)) { - newWidth = newWidth + (layout.toDevicePixels(fullscreen.size.width) - (onScreenLeft + width)); - } - - if (height && height < layout.toDevicePixels(fullscreen.size.height) && onScreenTop + height >= layout.toDevicePixels(safeArea.origin.y) + layout.toDevicePixels(safeArea.size.height)) { - newHeight = newHeight + (layout.toDevicePixels(fullscreen.size.height) - (onScreenTop + height)); - } - - const frameNew = CGRectMake(layout.toDeviceIndependentPixels(newLeft), layout.toDeviceIndependentPixels(newTop), layout.toDeviceIndependentPixels(newWidth), layout.toDeviceIndependentPixels(newHeight)); - nativeView.frame = frameNew; - } - } - - // if (leftInset || topInset) { - // const frameNew = CGRectMake(layout.toDeviceIndependentPixels(left), layout.toDeviceIndependentPixels(top), layout.toDeviceIndependentPixels(right - left + leftInset), layout.toDeviceIndependentPixels(bottom - top + topInset)); - // nativeView.frame = frameNew; - // const boundsOrigin = nativeView.bounds.origin; - // nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, frameNew.size.width, frameNew.size.height); - // } - // else { - const boundsOrigin = nativeView.bounds.origin; - nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, nativeView.frame.size.width, nativeView.frame.size.height); - // } - // } - - return nativeView.frame; - } - [clipToBoundsProperty.getDefault](): boolean { return false; } diff --git a/tns-core-modules/ui/layouts/stack-layout/stack-layout.ios.ts b/tns-core-modules/ui/layouts/stack-layout/stack-layout.ios.ts index b8c672f52..62804aa91 100644 --- a/tns-core-modules/ui/layouts/stack-layout/stack-layout.ios.ts +++ b/tns-core-modules/ui/layouts/stack-layout/stack-layout.ios.ts @@ -81,8 +81,10 @@ export class StackLayout extends StackLayoutBase { this.setMeasuredDimension(widthAndState, heightAndState); } - public onLayout(left: number, top: number, right: number, bottom: number, insets: {left, top, right, bottom}): void { + public onLayout(left: number, top: number, right: number, bottom: number): void { super.onLayout(left, top, right, bottom); + + const insets = this.getSafeAreaInsets(); if (this.orientation === "vertical") { this.layoutVertical(left, top, right, bottom, insets); } @@ -100,7 +102,6 @@ export class StackLayout extends StackLayoutBase { let childTop: number; let childLeft: number = paddingLeft; let childRight = right - left - paddingRight; - // let childRight = right - paddingRight; switch (this.verticalAlignment) { case VerticalAlignment.MIDDLE: diff --git a/tns-core-modules/ui/layouts/wrap-layout/wrap-layout.ios.ts b/tns-core-modules/ui/layouts/wrap-layout/wrap-layout.ios.ts index 2919c78ab..2d1d3a3d0 100644 --- a/tns-core-modules/ui/layouts/wrap-layout/wrap-layout.ios.ts +++ b/tns-core-modules/ui/layouts/wrap-layout/wrap-layout.ios.ts @@ -119,9 +119,10 @@ export class WrapLayout extends WrapLayoutBase { this.setMeasuredDimension(widthAndState, heightAndState); } - public onLayout(left: number, top: number, right: number, bottom: number, insets: { left, top, right, bottom }): void { + public onLayout(left: number, top: number, right: number, bottom: number): void { super.onLayout(left, top, right, bottom); + const insets = this.getSafeAreaInsets(); const isVertical = this.orientation === "vertical"; const paddingLeft = this.effectiveBorderLeftWidth + this.effectivePaddingLeft + insets.left; const paddingTop = this.effectiveBorderTopWidth + this.effectivePaddingTop + insets.top; diff --git a/tns-core-modules/ui/list-view/list-view-common.ts b/tns-core-modules/ui/list-view/list-view-common.ts index 447fc09ef..746b8527b 100644 --- a/tns-core-modules/ui/list-view/list-view-common.ts +++ b/tns-core-modules/ui/list-view/list-view-common.ts @@ -1,5 +1,5 @@ import { ListView as ListViewDefinition, ItemsSource, ItemEventData, TemplatedItemsView } from "."; -import { CoercibleProperty, CssProperty, Style, View, Template, KeyedTemplate, Length, Property, Color, Observable, EventData, CSSType } from "../core/view"; +import { CoercibleProperty, CssProperty, Style, View, ViewBase, ContainerView, Template, KeyedTemplate, Length, Property, Color, Observable, EventData, CSSType } from "../core/view"; import { parse, parseMultipleTemplates } from "../builder"; import { Label } from "../label"; import { ObservableArray, ChangedData } from "../../data/observable-array"; @@ -19,7 +19,7 @@ export module knownMultiTemplates { const autoEffectiveRowHeight = -1; @CSSType("ListView") -export abstract class ListViewBase extends View implements ListViewDefinition, TemplatedItemsView { +export abstract class ListViewBase extends ContainerView implements ListViewDefinition, TemplatedItemsView { public static itemLoadingEvent = "itemLoading"; public static itemTapEvent = "itemTap"; public static loadMoreItemsEvent = "loadMoreItems"; diff --git a/tns-core-modules/ui/list-view/list-view.ios.ts b/tns-core-modules/ui/list-view/list-view.ios.ts index afb6af08a..6858d3d6d 100644 --- a/tns-core-modules/ui/list-view/list-view.ios.ts +++ b/tns-core-modules/ui/list-view/list-view.ios.ts @@ -380,81 +380,6 @@ export class ListView extends ListViewBase { }); } - public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { - // if (!CGRectEqualToRect(nativeView.frame, frame)) { - // if (traceEnabled()) { - // traceWrite(this + ", Native setFrame: = " + NSStringFromCGRect(frame), traceCategories.Layout); - // } - // this._cachedFrame = frame; - // if (this._hasTransfrom) { - // // Always set identity transform before setting frame; - // const transform = nativeView.transform; - // nativeView.transform = CGAffineTransformIdentity; - // nativeView.frame = frame; - // nativeView.transform = transform; - // } - // else { - // nativeView.frame = frame; - // } - - nativeView.frame = frame; - - const safeArea = this.getSafeArea(); - const fullscreen = this.getFullscreenArea(); - const locationOnScreen = this.getLocationInWindow(); - const onScreenLeft = layout.toDevicePixels(layout.round(locationOnScreen.x)); - const onScreenTop = layout.toDevicePixels(layout.round(locationOnScreen.y)); - - let left = layout.toDevicePixels(frame.origin.x); - let top = layout.toDevicePixels(frame.origin.y); - let width = layout.toDevicePixels(frame.size.width); - let height = layout.toDevicePixels(frame.size.height); - - if (majorVersion > 10) { - // this._ios.insetsContentViewsToSafeArea = false; - - let newLeft = left; - let newTop = top; - let newWidth = width; - let newHeight = height; - - if (left !== 0 && onScreenLeft <= layout.toDevicePixels(safeArea.origin.x)) { - newLeft = layout.toDevicePixels(fullscreen.origin.x); - newWidth = width + onScreenLeft; - } - - if (top !== 0 && onScreenTop <= layout.toDevicePixels(safeArea.origin.y)) { - newTop = layout.toDevicePixels(fullscreen.origin.y); - newHeight = height + onScreenTop; - } - - if (width && width < layout.toDevicePixels(fullscreen.size.width) && onScreenLeft + width >= layout.toDevicePixels(safeArea.origin.x) + layout.toDevicePixels(safeArea.size.width)) { - newWidth = newWidth + (layout.toDevicePixels(fullscreen.size.width) - (onScreenLeft + width)); - } - - if (height && height < layout.toDevicePixels(fullscreen.size.height) && onScreenTop + height >= layout.toDevicePixels(safeArea.origin.y) + layout.toDevicePixels(safeArea.size.height)) { - newHeight = newHeight + (layout.toDevicePixels(fullscreen.size.height) - (onScreenTop + height)); - } - - const frameNew = CGRectMake(layout.toDeviceIndependentPixels(newLeft), layout.toDeviceIndependentPixels(newTop), layout.toDeviceIndependentPixels(newWidth), layout.toDeviceIndependentPixels(newHeight)); - nativeView.frame = frameNew; - } - - // if (leftInset || topInset) { - // const frameNew = CGRectMake(layout.toDeviceIndependentPixels(left), layout.toDeviceIndependentPixels(top), layout.toDeviceIndependentPixels(right - left + leftInset), layout.toDeviceIndependentPixels(bottom - top + topInset)); - // nativeView.frame = frameNew; - // const boundsOrigin = nativeView.bounds.origin; - // nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, frameNew.size.width, frameNew.size.height); - // } - // else { - const boundsOrigin = nativeView.bounds.origin; - nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, nativeView.frame.size.width, nativeView.frame.size.height); - // } - // } - - return nativeView.frame; - } - private _layoutCell(cellView: View, indexPath: NSIndexPath): number { if (cellView) { const rowHeight = this._effectiveRowHeight; diff --git a/tns-core-modules/ui/scroll-view/scroll-view.ios.ts b/tns-core-modules/ui/scroll-view/scroll-view.ios.ts index bde46340d..f1345c7e2 100644 --- a/tns-core-modules/ui/scroll-view/scroll-view.ios.ts +++ b/tns-core-modules/ui/scroll-view/scroll-view.ios.ts @@ -124,15 +124,6 @@ export class ScrollView extends ScrollViewBase { this._contentMeasuredWidth = this.effectiveMinWidth; this._contentMeasuredHeight = this.effectiveMinHeight; - // // `_automaticallyAdjustsScrollViewInsets` is set to true only if the first child - // // of UIViewController (Page, TabView e.g) is UIScrollView (ScrollView, ListView e.g). - // // On iOS 11 by default UIScrollView automatically adjusts the scroll view insets, but they s - // if (majorVersion > 10) { - // // Disable automatic adjustment of scroll view insets when ScrollView - // // is not the first child of UIViewController. - // this.nativeViewProtected.contentInsetAdjustmentBehavior = 2; - // } - if (child) { let childSize: { measuredWidth: number; measuredHeight: number }; if (this.orientation === "vertical") { @@ -141,10 +132,6 @@ export class ScrollView extends ScrollViewBase { childSize = View.measureChild(this, child, layout.makeMeasureSpec(0, layout.UNSPECIFIED), heightMeasureSpec); } - // const w = layout.toDeviceIndependentPixels(childSize.measuredWidth); - // const h = layout.toDeviceIndependentPixels(childSize.measuredHeight); - // this.nativeViewProtected.contentSize = CGSizeMake(w, h); - this._contentMeasuredWidth = Math.max(childSize.measuredWidth, this.effectiveMinWidth); this._contentMeasuredHeight = Math.max(childSize.measuredHeight, this.effectiveMinHeight); } @@ -155,29 +142,20 @@ export class ScrollView extends ScrollViewBase { this.setMeasuredDimension(widthAndState, heightAndState); } - public onLayout(left: number, top: number, right: number, bottom: number, insets?: {left, top, right, bottom}): void { + public onLayout(left: number, top: number, right: number, bottom: number): void { let width = (right - left); let height = (bottom - top); + const nativeView = this.nativeViewProtected; + if (majorVersion > 10) { // Disable automatic adjustment of scroll view insets // Consider exposing this as property with all 4 modes // https://developer.apple.com/documentation/uikit/uiscrollview/contentinsetadjustmentbehavior - this.nativeViewProtected.contentInsetAdjustmentBehavior = 2; + nativeView.contentInsetAdjustmentBehavior = 2; } - // let verticalInset: number; - const nativeView = this.nativeViewProtected; - // const inset = nativeView.adjustedContentInset; - // // Prior iOS 11 - // if (inset === undefined) { - // verticalInset = 0; - // // verticalInset = -layout.toDevicePixels(nativeView.contentOffset.y); - // // verticalInset += getTabBarHeight(this); - // } else { - // verticalInset = layout.toDevicePixels(inset.bottom + inset.top); - // } - + const insets = this.getSafeAreaInsets(); if (this.orientation === "horizontal") { width = Math.max(this._contentMeasuredWidth + insets.left + insets.right, width); } @@ -187,87 +165,6 @@ export class ScrollView extends ScrollViewBase { nativeView.contentSize = CGSizeMake(layout.toDeviceIndependentPixels(width), layout.toDeviceIndependentPixels(height)); View.layoutChild(this, this.layoutView, insets.left, insets.top, width, height); - - // if (this.orientation === "horizontal") { - // nativeView.contentSize = CGSizeMake(layout.toDeviceIndependentPixels(this._contentMeasuredWidth + insets.left + insets.right), layout.toDeviceIndependentPixels(height)); - // View.layoutChild(this, this.layoutView, 0, 0, Math.max(this._contentMeasuredWidth + insets.left + insets.right, width), height); - // } else { - // nativeView.contentSize = CGSizeMake(layout.toDeviceIndependentPixels(width), layout.toDeviceIndependentPixels(this._contentMeasuredHeight + insets.top + insets.bottom)); - // View.layoutChild(this, this.layoutView, 0, 0, width, Math.max(this._contentMeasuredHeight + insets.top + insets.bottom, height)); - // } - } - - public _setNativeViewFrame(nativeView: UIView, frame: CGRect) { - // if (!CGRectEqualToRect(nativeView.frame, frame)) { - // if (traceEnabled()) { - // traceWrite(this + ", Native setFrame: = " + NSStringFromCGRect(frame), traceCategories.Layout); - // } - // this._cachedFrame = frame; - // if (this._hasTransfrom) { - // // Always set identity transform before setting frame; - // const transform = nativeView.transform; - // nativeView.transform = CGAffineTransformIdentity; - // nativeView.frame = frame; - // nativeView.transform = transform; - // } - // else { - // nativeView.frame = frame; - // } - - nativeView.frame = frame; - - const safeArea = this.getSafeArea(); - const fullscreen = this.getFullscreenArea(); - const locationOnScreen = this.getLocationInWindow(); - const onScreenLeft = layout.round(layout.toDevicePixels(locationOnScreen.x)); - const onScreenTop = layout.round(layout.toDevicePixels(locationOnScreen.y)); - - let left = layout.toDevicePixels(frame.origin.x); - let top = layout.toDevicePixels(frame.origin.y); - let width = layout.toDevicePixels(frame.size.width); - let height = layout.toDevicePixels(frame.size.height); - - if (majorVersion > 10) { - let newLeft = left; - let newTop = top; - let newWidth = width; - let newHeight = height; - - if (left !== 0 && onScreenLeft <= layout.toDevicePixels(safeArea.origin.x)) { - newLeft = layout.toDevicePixels(fullscreen.origin.x); - newWidth = width + onScreenLeft; - } - - if (top !== 0 && onScreenTop <= layout.toDevicePixels(safeArea.origin.y)) { - newTop = layout.toDevicePixels(fullscreen.origin.y); - newHeight = height + onScreenTop; - } - - if (width && width < layout.toDevicePixels(fullscreen.size.width) && onScreenLeft + width >= layout.toDevicePixels(safeArea.origin.x) + layout.toDevicePixels(safeArea.size.width)) { - newWidth = newWidth + (layout.toDevicePixels(fullscreen.size.width) - (onScreenLeft + width)); - } - - if (height && height < layout.toDevicePixels(fullscreen.size.height) && onScreenTop + height >= layout.toDevicePixels(safeArea.origin.y) + layout.toDevicePixels(safeArea.size.height)) { - newHeight = newHeight + (layout.toDevicePixels(fullscreen.size.height) - (onScreenTop + height)); - } - - const frameNew = CGRectMake(layout.toDeviceIndependentPixels(newLeft), layout.toDeviceIndependentPixels(newTop), layout.toDeviceIndependentPixels(newWidth), layout.toDeviceIndependentPixels(newHeight)); - nativeView.frame = frameNew; - } - - // if (leftInset || topInset) { - // const frameNew = CGRectMake(layout.toDeviceIndependentPixels(left), layout.toDeviceIndependentPixels(top), layout.toDeviceIndependentPixels(right - left + leftInset), layout.toDeviceIndependentPixels(bottom - top + topInset)); - // nativeView.frame = frameNew; - // const boundsOrigin = nativeView.bounds.origin; - // nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, frameNew.size.width, frameNew.size.height); - // } - // else { - const boundsOrigin = nativeView.bounds.origin; - nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, nativeView.frame.size.width, nativeView.frame.size.height); - // } - // } - - return nativeView.frame; } public _onOrientationChanged() {