From f01403a419549a4b03b5c5137e4557633314f538 Mon Sep 17 00:00:00 2001 From: Martin Yankov Date: Wed, 26 Sep 2018 18:36:30 +0300 Subject: [PATCH] fix nested viewcontrollers top insets --- tests/app/ui/layouts/safe-area-tests.ts | 504 +++++++++++++++++++++- tns-core-modules/ui/core/view/view.ios.ts | 15 +- 2 files changed, 515 insertions(+), 4 deletions(-) diff --git a/tests/app/ui/layouts/safe-area-tests.ts b/tests/app/ui/layouts/safe-area-tests.ts index 285f01be3..860b81abc 100644 --- a/tests/app/ui/layouts/safe-area-tests.ts +++ b/tests/app/ui/layouts/safe-area-tests.ts @@ -57,14 +57,38 @@ export class SafeAreaTests extends testModule.UITest { }; }; + private layout_insets_top_action_bar_test(layout: view.View) { + const app = iosUtils.getter(UIApplication, UIApplication.sharedApplication); + const statusBarHeight = round(dipToDp(app.statusBarFrame.size.height)); + const actionBarHeight = round(dipToDp(layout.page.actionBar.nativeViewProtected.frame.size.height)); + const topInset = statusBarHeight + actionBarHeight; + + const insets = layout.getSafeAreaInsets(); + equal(insets.top, topInset, `${layout}.topInset - actual:${insets.top}; expected: ${topInset}`) + } + + private layout_insets_top_action_bar_hidden_test(layout: view.View) { + const app = iosUtils.getter(UIApplication, UIApplication.sharedApplication); + const statusBarHeight = round(dipToDp(app.statusBarFrame.size.height)); + const topInset = statusBarHeight; + + const insets = layout.getSafeAreaInsets(); + equal(insets.top, topInset, `${layout}.topInset - actual:${insets.top}; expected: ${topInset}`) + } + + private layout_insets_top_action_bar_flat_test(layout: view.View) { + const insets = layout.getSafeAreaInsets(); + equal(insets.top, 0, `${layout}.topInset - actual:${insets.top}; expected: ${0}`) + } + private layout_in_full_screen_test(layout: view.View, pageOptions?: helper.PageOptions) { let expectedTop = 0; - if (pageOptions && pageOptions.actionBarFlat) { - const actionBarHeight = round(dipToDp(layout.page.actionBar.nativeViewProtected.frame.size.height)); + if (pageOptions && (pageOptions.actionBarFlat)) { const app = iosUtils.getter(UIApplication, UIApplication.sharedApplication); const statusBarHeight = round(dipToDp(app.statusBarFrame.size.height)); + const actionBarHeight = round(dipToDp(layout.page.actionBar.nativeViewProtected.frame.size.height)); - expectedTop = actionBarHeight + statusBarHeight; + expectedTop = statusBarHeight + actionBarHeight; } const l = left(layout); @@ -109,6 +133,85 @@ export class SafeAreaTests extends testModule.UITest { this.absolute_in_full_screen({ tabBar: true }); } + public test_absolute_in_full_screen_tab_bar_action_bar() { + this.absolute_in_full_screen({ actionBar: true, tabBar: true }); + } + + public test_absolute_insets_top_action_bar() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true } + ); + } + + public test_absolute_insets_top_action_bar_hidden() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { actionBarHidden: true } + ); + } + + public test_absolute_insets_top_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_flat_test(root); + }, + { actionBarFlat: true } + ); + } + + public test_absolute_insets_top_tab_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { tabBar: true } + ); + } + + public test_absolute_insets_top_tab_bar_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true, tabBar: true } + ); + } + private absolute_children_components_in_safe_area(pageOptions?: helper.PageOptions) { const snippet = ` @@ -228,6 +331,85 @@ export class SafeAreaTests extends testModule.UITest { this.dock_in_full_screen({ tabBar: true }); } + public test_dock_in_full_screen_tab_bar_action_bar() { + this.dock_in_full_screen({ actionBar: true, tabBar: true }); + } + + public test_dock_insets_top_action_bar() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true } + ); + } + + public test_dock_insets_top_action_bar_hidden() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { actionBarHidden: true } + ); + } + + public test_dock_insets_top_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_flat_test(root); + }, + { actionBarFlat: true } + ); + } + + public test_dock_insets_top_tab_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { tabBar: true } + ); + } + + public test_dock_insets_top_tab_bar_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true, tabBar: true } + ); + } + private dock_children_components_in_safe_area(pageOptions?: helper.PageOptions) { const snippet = ` @@ -367,6 +549,85 @@ export class SafeAreaTests extends testModule.UITest { this.flexbox_in_full_screen({ tabBar: true }); } + public test_flexbox_in_full_screen_tab_bar_action_bar() { + this.flexbox_in_full_screen({ actionBar: true, tabBar: true }); + } + + public test_flexbox_insets_top_action_bar() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true } + ); + } + + public test_flexbox_insets_top_action_bar_hidden() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { actionBarHidden: true } + ); + } + + public test_flexbox_insets_top_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_flat_test(root); + }, + { actionBarFlat: true } + ); + } + + public test_flexbox_insets_top_tab_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { tabBar: true } + ); + } + + public test_flexbox_insets_top_tab_bar_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true, tabBar: true } + ); + } + private flex_column_children_components_in_safe_area(pageOptions?: helper.PageOptions) { const snippet = ` @@ -582,6 +843,85 @@ export class SafeAreaTests extends testModule.UITest { this.grid_layout_in_full_screen({ tabBar: true }); } + public test_grid_layout_in_full_screen_tab_bar_action_bar() { + this.grid_layout_in_full_screen({ actionBar: true, tabBar: true }); + } + + public test_grid_insets_top_action_bar() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true } + ); + } + + public test_grid_insets_top_action_bar_hidden() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { actionBarHidden: true } + ); + } + + public test_grid_insets_top_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_flat_test(root); + }, + { actionBarFlat: true } + ); + } + + public test_grid_insets_top_tab_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { tabBar: true } + ); + } + + public test_grid_insets_top_tab_bar_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true, tabBar: true } + ); + } + private grid_component_cells_layout_in_safe_area(pageOptions?: helper.PageOptions) { const snippet = ` @@ -738,6 +1078,85 @@ export class SafeAreaTests extends testModule.UITest { this.stack_in_full_screen({ tabBar: true }); } + public test_stack_in_full_screen_tab_bar_action_bar() { + this.stack_in_full_screen({ actionBar: true, tabBar: true }); + } + + public test_stack_insets_top_action_bar() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true } + ); + } + + public test_stack_insets_top_action_bar_hidden() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { actionBarHidden: true } + ); + } + + public test_stack_insets_top_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_flat_test(root); + }, + { actionBarFlat: true } + ); + } + + public test_stack_insets_top_tab_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { tabBar: true } + ); + } + + public test_stack_insets_top_tab_bar_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true, tabBar: true } + ); + } + private stack_horizontal_children_components_in_safe_area(pageOptions?: helper.PageOptions) { const snippet = ` @@ -873,6 +1292,85 @@ export class SafeAreaTests extends testModule.UITest { this.wrap_in_full_screen({ tabBar: true }); } + public test_wrap_in_full_screen_tab_bar_action_bar() { + this.wrap_in_full_screen({ actionBar: true, tabBar: true }); + } + + public test_wrap_insets_top_action_bar() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true } + ); + } + + public test_wrap_insets_top_action_bar_hidden() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { actionBarHidden: true } + ); + } + + public test_wrap_insets_top_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_flat_test(root); + }, + { actionBarFlat: true } + ); + } + + public test_wrap_insets_top_tab_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_hidden_test(root); + }, + { tabBar: true } + ); + } + + public test_wrap_insets_top_tab_bar_action_bar_flat() { + const snippet = ` + + `; + + this.executeSnippet( + this.getViews(snippet), + this.noop, + ({ root }) => { + this.layout_insets_top_action_bar_test(root); + }, + { actionBar: true, tabBar: true } + ); + } + private wrap_horizontal_children_components_in_safe_area(pageOptions?: helper.PageOptions) { const snippet = ` diff --git a/tns-core-modules/ui/core/view/view.ios.ts b/tns-core-modules/ui/core/view/view.ios.ts index fc0e6b27f..097a2cfe2 100644 --- a/tns-core-modules/ui/core/view/view.ios.ts +++ b/tns-core-modules/ui/core/view/view.ios.ts @@ -5,7 +5,7 @@ import { booleanConverter, Property } from "../view"; import { ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty, - traceEnabled, traceWrite, traceCategories, traceError, traceMessageType + traceEnabled, traceWrite, traceCategories, traceError, traceMessageType, getAncestor } from "./view-common"; import { ios as iosBackground, Background } from "../../styling/background"; @@ -691,6 +691,19 @@ export namespace ios { } export function layoutView(controller: UIViewController, owner: View): void { + // apply parent page additional top insets if any. The scenario is when there is a parent page with action bar. + const parentPage = getAncestor(owner, "Page"); + if (parentPage) { + const parentPageInsetsTop = parentPage.viewController.view.safeAreaInsets.top; + const currentInsetsTop = controller.view.safeAreaInsets.top; + const additionalInsetsTop = parentPageInsetsTop - currentInsetsTop; + + if (additionalInsetsTop > 0) { + const additionalInsets = new UIEdgeInsets({ top: additionalInsetsTop, left: 0, bottom: 0, right: 0 }); + controller.additionalSafeAreaInsets = additionalInsets; + } + } + let layoutGuide = controller.view.safeAreaLayoutGuide; if (!layoutGuide) { traceWrite(`safeAreaLayoutGuide during layout of ${owner}. Creating fallback constraints, but layout might be wrong.`,