Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions apps/automated/src/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,19 @@ allTests['STACKLAYOUT'] = stackLayoutTests;
import * as flexBoxLayoutTests from './ui/layouts/flexbox-layout-tests';
allTests['FLEXBOXLAYOUT'] = flexBoxLayoutTests;

// import * as safeAreaLayoutTests from './ui/layouts/safe-area-tests';
// import * as safeAreaListViewtTests from './ui/list-view/list-view-safe-area-tests';
// import * as scrollViewSafeAreaTests from './ui/scroll-view/scroll-view-safe-area-tests';
// import * as repeaterSafeAreaTests from './ui/repeater/repeater-safe-area-tests';
// import * as webViewSafeAreaTests from './ui/web-view/web-view-safe-area-tests';

// if (isIOS && Utils.ios.MajorVersion > 10) {
// allTests['SAFEAREALAYOUT'] = safeAreaLayoutTests;
// allTests['SAFEAREA-LISTVIEW'] = safeAreaListViewtTests;
// allTests['SAFEAREA-SCROLL-VIEW'] = scrollViewSafeAreaTests;
// allTests['SAFEAREA-REPEATER'] = repeaterSafeAreaTests;
// allTests['SAFEAREA-WEBVIEW'] = webViewSafeAreaTests;
// }
import * as safeAreaLayoutTests from './ui/layouts/safe-area-tests';
import * as safeAreaListViewtTests from './ui/list-view/list-view-safe-area-tests';
import * as scrollViewSafeAreaTests from './ui/scroll-view/scroll-view-safe-area-tests';
import * as repeaterSafeAreaTests from './ui/repeater/repeater-safe-area-tests';
import * as webViewSafeAreaTests from './ui/web-view/web-view-safe-area-tests';

if (isIOS && Utils.ios.MajorVersion > 10) {
allTests['SAFEAREALAYOUT'] = safeAreaLayoutTests;
allTests['SAFEAREA-LISTVIEW'] = safeAreaListViewtTests;
allTests['SAFEAREA-SCROLL-VIEW'] = scrollViewSafeAreaTests;
allTests['SAFEAREA-REPEATER'] = repeaterSafeAreaTests;
allTests['SAFEAREA-WEBVIEW'] = webViewSafeAreaTests;
}

import * as rootViewsCssClassesTests from './ui/styling/root-views-css-classes-tests';
allTests['ROOT-VIEWS-CSS-CLASSES'] = rootViewsCssClassesTests;
Expand Down
89 changes: 45 additions & 44 deletions packages/core/ui/core/view/view-helper/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,61 +92,62 @@ class UILayoutViewController extends UIViewController {
}
layoutOwner(force = false) {
const owner = this.owner?.deref();
if (!force && !!owner.nativeViewProtected?.layer.needsLayout?.()) {
if (!owner) {
return;
}
if (!force && owner.isLayoutValid && !owner.nativeViewProtected?.layer.needsLayout?.()) {
// we skip layout if the view is not yet laid out yet
// this usually means that viewDidLayoutSubviews will be called again
// so doing a layout pass now will layout with the wrong parameters
return;
}

if (owner) {
if (majorVersion >= 11) {
// Handle nested UILayoutViewController safe area application.
// Currently, UILayoutViewController can be nested only in a TabView.
// The TabView itself is handled by the OS, so we check the TabView's parent (usually a Page, but can be a Layout).
const tabViewItem = owner.parent;
const tabView = tabViewItem && tabViewItem.parent;
let parent = tabView && tabView.parent;

// Handle Angular scenario where TabView is in a ProxyViewContainer
// It is possible to wrap components in ProxyViewContainers indefinitely
// Not using instanceof ProxyViewContainer to avoid circular dependency
// TODO: Try moving UILayoutViewController out of view module
while (parent && !parent.nativeViewProtected) {
parent = parent.parent;
if (majorVersion >= 11) {
// Handle nested UILayoutViewController safe area application.
// Currently, UILayoutViewController can be nested only in a TabView.
// The TabView itself is handled by the OS, so we check the TabView's parent (usually a Page, but can be a Layout).
const tabViewItem = owner.parent;
const tabView = tabViewItem && tabViewItem.parent;
let parent = tabView && tabView.parent;

// Handle Angular scenario where TabView is in a ProxyViewContainer
// It is possible to wrap components in ProxyViewContainers indefinitely
// Not using instanceof ProxyViewContainer to avoid circular dependency
// TODO: Try moving UILayoutViewController out of view module
while (parent && !parent.nativeViewProtected) {
parent = parent.parent;
}

if (parent) {
const parentPageInsetsTop = parent.nativeViewProtected.safeAreaInsets.top;
const parentPageInsetsBottom = parent.nativeViewProtected.safeAreaInsets.bottom;
let currentInsetsTop = this.view.safeAreaInsets.top;
let currentInsetsBottom = this.view.safeAreaInsets.bottom;

// Safe area insets include additional safe area insets too, so subtract old values
if (this.additionalSafeAreaInsets) {
currentInsetsTop -= this.additionalSafeAreaInsets.top;
currentInsetsBottom -= this.additionalSafeAreaInsets.bottom;
}

if (parent) {
const parentPageInsetsTop = parent.nativeViewProtected.safeAreaInsets.top;
const parentPageInsetsBottom = parent.nativeViewProtected.safeAreaInsets.bottom;
let currentInsetsTop = this.view.safeAreaInsets.top;
let currentInsetsBottom = this.view.safeAreaInsets.bottom;

// Safe area insets include additional safe area insets too, so subtract old values
if (this.additionalSafeAreaInsets) {
currentInsetsTop -= this.additionalSafeAreaInsets.top;
currentInsetsBottom -= this.additionalSafeAreaInsets.bottom;
}

const additionalInsetsTop = Math.max(parentPageInsetsTop - currentInsetsTop, 0);
const additionalInsetsBottom = Math.max(parentPageInsetsBottom - currentInsetsBottom, 0);

if (additionalInsetsTop > 0 || additionalInsetsBottom > 0) {
const additionalInsets = new UIEdgeInsets({
top: additionalInsetsTop,
left: 0,
bottom: additionalInsetsBottom,
right: 0,
});
this.additionalSafeAreaInsets = additionalInsets;
} else {
this.additionalSafeAreaInsets = null;
}
const additionalInsetsTop = Math.max(parentPageInsetsTop - currentInsetsTop, 0);
const additionalInsetsBottom = Math.max(parentPageInsetsBottom - currentInsetsBottom, 0);

if (additionalInsetsTop > 0 || additionalInsetsBottom > 0) {
const additionalInsets = new UIEdgeInsets({
top: additionalInsetsTop,
left: 0,
bottom: additionalInsetsBottom,
right: 0,
});
this.additionalSafeAreaInsets = additionalInsets;
} else {
this.additionalSafeAreaInsets = null;
}
}

IOSHelper.layoutView(this, owner);
}

IOSHelper.layoutView(this, owner);
}

public viewWillAppear(animated: boolean): void {
Expand Down
94 changes: 48 additions & 46 deletions packages/core/ui/page/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,63 +312,65 @@ class UIViewControllerImpl extends UIViewController {

layoutOwner(force = false) {
const owner = this._owner?.deref();
if (!force && !!owner.nativeViewProtected?.layer.needsLayout?.()) {
if (!owner) {
return;
}
if (!force && owner.isLayoutValid && !owner.nativeViewProtected?.layer.needsLayout?.()) {
// we skip layout if the view is not yet laid out yet
// this usually means that viewDidLayoutSubviews will be called again
// so doing a layout pass now will layout with the wrong parameters
return;
}
if (owner) {
// layout(owner.actionBar)
// layout(owner.content)

if (majorVersion >= 11) {
// Handle nested Page safe area insets application.
// A Page is nested if its Frame has a parent.
// If the Page is nested, cross check safe area insets on top and bottom with Frame parent.
const frame = owner.parent;
// There is a legacy scenario where Page is not in a Frame - the root of a Modal View, so it has no parent.
let frameParent = frame && frame.parent;

// Handle Angular scenario where TabView is in a ProxyViewContainer
// It is possible to wrap components in ProxyViewContainers indefinitely
// Not using instanceof ProxyViewContainer to avoid circular dependency
// TODO: Try moving UIViewControllerImpl out of page module
while (frameParent && !frameParent.nativeViewProtected) {
frameParent = frameParent.parent;
}

if (frameParent) {
const parentPageInsetsTop = frameParent.nativeViewProtected.safeAreaInsets.top;
const parentPageInsetsBottom = frameParent.nativeViewProtected.safeAreaInsets.bottom;
let currentInsetsTop = this.view.safeAreaInsets.top;
let currentInsetsBottom = this.view.safeAreaInsets.bottom;
// layout(owner.actionBar)
// layout(owner.content)

// Safe area insets include additional safe area insets too, so subtract old values
if (this.additionalSafeAreaInsets) {
currentInsetsTop -= this.additionalSafeAreaInsets.top;
currentInsetsBottom -= this.additionalSafeAreaInsets.bottom;
}
if (majorVersion >= 11) {
// Handle nested Page safe area insets application.
// A Page is nested if its Frame has a parent.
// If the Page is nested, cross check safe area insets on top and bottom with Frame parent.
const frame = owner.parent;
// There is a legacy scenario where Page is not in a Frame - the root of a Modal View, so it has no parent.
let frameParent = frame && frame.parent;

const additionalInsetsTop = Math.max(parentPageInsetsTop - currentInsetsTop, 0);
const additionalInsetsBottom = Math.max(parentPageInsetsBottom - currentInsetsBottom, 0);

if (additionalInsetsTop > 0 || additionalInsetsBottom > 0) {
const additionalInsets = new UIEdgeInsets({
top: additionalInsetsTop,
left: 0,
bottom: additionalInsetsBottom,
right: 0,
});
this.additionalSafeAreaInsets = additionalInsets;
} else {
this.additionalSafeAreaInsets = null;
}
}
// Handle Angular scenario where TabView is in a ProxyViewContainer
// It is possible to wrap components in ProxyViewContainers indefinitely
// Not using instanceof ProxyViewContainer to avoid circular dependency
// TODO: Try moving UIViewControllerImpl out of page module
while (frameParent && !frameParent.nativeViewProtected) {
frameParent = frameParent.parent;
}

IOSHelper.layoutView(this, owner);
if (frameParent) {
const parentPageInsetsTop = frameParent.nativeViewProtected.safeAreaInsets.top;
const parentPageInsetsBottom = frameParent.nativeViewProtected.safeAreaInsets.bottom;
let currentInsetsTop = this.view.safeAreaInsets.top;
let currentInsetsBottom = this.view.safeAreaInsets.bottom;

// Safe area insets include additional safe area insets too, so subtract old values
if (this.additionalSafeAreaInsets) {
currentInsetsTop -= this.additionalSafeAreaInsets.top;
currentInsetsBottom -= this.additionalSafeAreaInsets.bottom;
}

const additionalInsetsTop = Math.max(parentPageInsetsTop - currentInsetsTop, 0);
const additionalInsetsBottom = Math.max(parentPageInsetsBottom - currentInsetsBottom, 0);

if (additionalInsetsTop > 0 || additionalInsetsBottom > 0) {
const additionalInsets = new UIEdgeInsets({
top: additionalInsetsTop,
left: 0,
bottom: additionalInsetsBottom,
right: 0,
});
this.additionalSafeAreaInsets = additionalInsets;
} else {
this.additionalSafeAreaInsets = null;
}
}
}

IOSHelper.layoutView(this, owner);
}

// Mind implementation for other controllerss
Expand Down