mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-15 19:26:42 +08:00
Generated platforms declarations for iOS 11
Fixed broken unit-tests ios layout now run only for the innermost viewcontoller ios layout for viewcontrollers now implemented with constraints Added ios11 safeAreas layout support onMeasure back for frame and tab-view so that they won't throw exception if measure is called on them Page parents layout updated after page is layout so that inner layout flags are correct
This commit is contained in:
@ -356,11 +356,9 @@ export function waitUntilReady(isReady: () => boolean, timeoutSec: number = 3, s
|
||||
}
|
||||
|
||||
if (Application.ios) {
|
||||
// const waitTime = 1 / 10000;
|
||||
const timeoutMs = timeoutSec * 1000;
|
||||
let totalWaitTime = 0;
|
||||
while (true) {
|
||||
// const nsDate = <any>NSDate.dateWithTimeIntervalSinceNow(waitTime);
|
||||
const begin = time();
|
||||
const currentRunLoop = utils.ios.getter(NSRunLoop, NSRunLoop.currentRunLoop);
|
||||
currentRunLoop.limitDateForMode(currentRunLoop.currentMode);
|
||||
|
@ -15,6 +15,7 @@ exports.pageLoaded = pageLoaded;
|
||||
// << article-set-bindingcontext
|
||||
import * as TKUnit from "../../TKUnit";
|
||||
import * as helper from "../helper";
|
||||
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
|
||||
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
|
||||
import { View, PercentLength, Observable, unsetValue, EventData, isIOS } from "tns-core-modules/ui/core/view";
|
||||
import { Label } from "tns-core-modules/ui/label";
|
||||
@ -562,31 +563,40 @@ export function test_percent_width_and_height_support() {
|
||||
|
||||
export function test_percent_margin_support() {
|
||||
const testPage = new Page();
|
||||
testPage.id = "ttest_percent_margin_support";
|
||||
|
||||
const gridLayout = new GridLayout();
|
||||
const stackLayout = new StackLayout();
|
||||
stackLayout.margin = "10%";
|
||||
testPage.content = stackLayout;
|
||||
gridLayout.addChild(stackLayout);
|
||||
testPage.content = gridLayout;
|
||||
|
||||
const pageWidth = testPage.getMeasuredWidth();
|
||||
const pageHeight = testPage.getMeasuredHeight()
|
||||
helper.navigate(() => testPage);
|
||||
|
||||
const marginLeft = pageWidth * 0.1;
|
||||
const marginTop = pageHeight * 0.1;
|
||||
const parentBounds = gridLayout._getCurrentLayoutBounds();
|
||||
const parentWidth = parentBounds.right - parentBounds.left;
|
||||
const parentHeight = parentBounds.bottom - parentBounds.top;
|
||||
|
||||
const bounds = stackLayout._getCurrentLayoutBounds();
|
||||
TKUnit.assertEqual(bounds.left, Math.round(marginLeft), "Page's content LEFT position incorrect");
|
||||
TKUnit.assertEqual(bounds.top, Math.round(marginTop), "Page's content TOP position incorrect");
|
||||
TKUnit.assertEqual(bounds.right, Math.round(marginLeft + pageWidth), "Page's content RIGHT position incorrect");
|
||||
TKUnit.assertEqual(bounds.bottom, Math.round(marginTop + pageHeight), "Page's content BOTTOM position incorrect");
|
||||
const marginLeft = Math.round(parentWidth * 0.1);
|
||||
const marginTop = Math.round(parentHeight * 0.1);
|
||||
|
||||
let bounds = stackLayout._getCurrentLayoutBounds();
|
||||
TKUnit.assertEqual(Math.round(bounds.left), marginLeft, "Stack LEFT position incorrect");
|
||||
TKUnit.assertEqual(Math.round(bounds.top), marginTop, "Stack TOP position incorrect");
|
||||
TKUnit.assertEqual(Math.round(bounds.bottom - bounds.top), parentHeight - (2 * marginTop), "Stack HEIGHT incorrect");
|
||||
TKUnit.assertEqual(Math.round(bounds.right - bounds.left), parentWidth - (2 * marginLeft), "Stack WIDTH incorrect");
|
||||
TKUnit.assertEqual(Math.round(bounds.right), parentWidth - marginLeft, "Stack RIGHT position incorrect");
|
||||
TKUnit.assertEqual(Math.round(bounds.bottom), parentHeight - marginTop, "Stack BOTTOM position incorrect");
|
||||
|
||||
//reset values.
|
||||
testPage.margin = "0";
|
||||
stackLayout.margin = "0";
|
||||
TKUnit.waitUntilReady(() => stackLayout.isLayoutValid);
|
||||
|
||||
TKUnit.assertTrue(PercentLength.equals(testPage.marginLeft, 0));
|
||||
TKUnit.assertTrue(PercentLength.equals(testPage.marginTop, 0));
|
||||
TKUnit.assertTrue(PercentLength.equals(testPage.marginRight, 0));
|
||||
TKUnit.assertTrue(PercentLength.equals(testPage.marginBottom, 0));
|
||||
bounds = stackLayout._getCurrentLayoutBounds();
|
||||
TKUnit.assertEqual(bounds.left, 0, "Stack LEFT position incorrect");
|
||||
TKUnit.assertEqual(bounds.top, 0, "Stack TOP position incorrect");
|
||||
TKUnit.assertEqual(bounds.bottom - bounds.top, parentHeight, "Stack HEIGHT incorrect");
|
||||
TKUnit.assertEqual(bounds.right - bounds.left, parentWidth, "Stack WIDTH incorrect");
|
||||
TKUnit.assertEqual(bounds.right, parentWidth, "Stack RIGHT position incorrect");
|
||||
TKUnit.assertEqual(bounds.bottom, parentHeight, "Stack BOTTOM position incorrect");
|
||||
}
|
||||
|
||||
//export function test_ModalPage_Layout_is_Correct() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { TabView, TabViewItem } from "tns-core-modules/ui/tab-view";
|
||||
import { Page, layout, View, EventData } from "tns-core-modules/ui/page";
|
||||
import { ios as iosView } from "tns-core-modules/ui/core/view";
|
||||
import { Label } from "tns-core-modules/ui/label";
|
||||
import { topmost } from "tns-core-modules/ui/frame";
|
||||
import * as uiUtils from "tns-core-modules/ui/utils";
|
||||
@ -72,6 +73,11 @@ function getHeight(view: View): number {
|
||||
return bounds.bottom - bounds.top;
|
||||
}
|
||||
|
||||
function getNativeHeight(view: View): number {
|
||||
const bounds = view.nativeViewProtected.frame;
|
||||
return layout.toDevicePixels(bounds.size.height);
|
||||
}
|
||||
|
||||
export function test_correct_layout_scrollable_content_false() {
|
||||
const page = new Page();
|
||||
(<any>page).scrollableContent = false;
|
||||
@ -82,6 +88,7 @@ export function test_correct_layout_scrollable_content_false() {
|
||||
const tabItem = new TabViewItem();
|
||||
tabItem.title = "Item";
|
||||
const lbl = new Label();
|
||||
(<any>lbl).scrollableContent = false;
|
||||
tabItem.view = lbl;
|
||||
tabView.items = [tabItem];
|
||||
|
||||
@ -94,24 +101,28 @@ export function test_correct_layout_scrollable_content_false() {
|
||||
const screenHeight = layout.toDevicePixels(UIScreen.mainScreen.bounds.size.height);
|
||||
|
||||
let pageHeight = getHeight(page);
|
||||
let expectedPageHeight = screenHeight - statusBarHeight;
|
||||
TKUnit.assertEqual(pageHeight, expectedPageHeight, "page.height !== screenHeight - statusBar");
|
||||
let expectedPageHeight = screenHeight;
|
||||
TKUnit.assertEqual(pageHeight, expectedPageHeight, "page.height !== screenHeight");
|
||||
|
||||
let contentHeight = getHeight(lbl);
|
||||
let contentNativeHeight = getNativeHeight(lbl);
|
||||
let expectedLabelHeight = screenHeight - statusBarHeight - tabBarHeight;
|
||||
TKUnit.assertEqual(contentHeight, expectedLabelHeight, "lbl.height !== screenHeight - statusBar - tabBar");
|
||||
TKUnit.assertEqual(contentNativeHeight, expectedLabelHeight, "lbl.height !== screenHeight - statusBar - tabBar");
|
||||
|
||||
page.actionBarHidden = false;
|
||||
TKUnit.waitUntilReady(() => page.isLayoutValid);
|
||||
|
||||
pageHeight = getHeight(page);
|
||||
const navBarHeight = uiUtils.ios.getActualHeight(page.frame.ios.controller.navigationBar);
|
||||
expectedPageHeight = screenHeight - statusBarHeight - navBarHeight;
|
||||
TKUnit.assertEqual(pageHeight, expectedPageHeight, "page.height !== screenHeight - statusBar - navBarHeight");
|
||||
expectedPageHeight = screenHeight;
|
||||
TKUnit.assertEqual(pageHeight, expectedPageHeight, "page.height !== screenHeight");
|
||||
|
||||
contentHeight = getHeight(lbl);
|
||||
contentNativeHeight = getNativeHeight(lbl);
|
||||
expectedLabelHeight = screenHeight - statusBarHeight - tabBarHeight - navBarHeight;
|
||||
TKUnit.assertEqual(contentHeight, expectedLabelHeight, "lbl.height !== screenHeight - statusBarHeight - tabBarHeight - navBarHeight");
|
||||
TKUnit.assertEqual(contentNativeHeight, expectedLabelHeight, "lbl.height !== screenHeight - statusBarHeight - tabBarHeight - navBarHeight");
|
||||
}
|
||||
|
||||
export function test_correct_layout_scrollable_content_true() {
|
||||
@ -137,12 +148,12 @@ export function test_correct_layout_scrollable_content_true() {
|
||||
const screenHeight = layout.toDevicePixels(UIScreen.mainScreen.bounds.size.height);
|
||||
|
||||
let pageHeight = getHeight(page);
|
||||
let expectedPageHeight = screenHeight - statusBarHeight;
|
||||
TKUnit.assertEqual(pageHeight, expectedPageHeight, "page.height !== screenHeight - statusBar");
|
||||
let expectedPageHeight = screenHeight;
|
||||
TKUnit.assertEqual(pageHeight, expectedPageHeight, "page.height !== screenHeight");
|
||||
|
||||
let contentHeight = getHeight(lbl);
|
||||
let expectedLabelHeight = screenHeight - statusBarHeight;
|
||||
TKUnit.assertEqual(contentHeight, expectedLabelHeight, "lbl.height !== screenHeight - statusBar - tabBar");
|
||||
TKUnit.assertEqual(contentHeight, expectedLabelHeight, "lbl.height !== screenHeight - statusBar");
|
||||
|
||||
page.actionBarHidden = false;
|
||||
TKUnit.waitUntilReady(() => page.isLayoutValid);
|
||||
|
@ -1,26 +1,26 @@
|
||||
import * as TKUnit from "../../TKUnit";
|
||||
import * as app from "tns-core-modules/application";
|
||||
import * as button from "tns-core-modules/ui/button";
|
||||
import * as testModule from "../../ui-test";
|
||||
import { Button } from "tns-core-modules/ui/button";
|
||||
import { Page, isIOS } from "tns-core-modules/ui/page";
|
||||
import { UITest } from "../../ui-test";
|
||||
import * as layoutHelper from "../layouts/layout-helper";
|
||||
import { Page } from "tns-core-modules/ui/page";
|
||||
import * as frame from "tns-core-modules/ui/frame";
|
||||
import * as helper from "../helper";
|
||||
|
||||
// >> article-require-scrollview-module
|
||||
import * as scrollViewModule from "tns-core-modules/ui/scroll-view";
|
||||
import { ScrollView, ScrollEventData } from "tns-core-modules/ui/scroll-view";
|
||||
// << article-require-scrollview-module
|
||||
|
||||
class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
class ScrollLayoutTest extends UITest<ScrollView> {
|
||||
|
||||
public create(): scrollViewModule.ScrollView {
|
||||
let scrollView = new scrollViewModule.ScrollView();
|
||||
public create(): ScrollView {
|
||||
const scrollView = new ScrollView();
|
||||
scrollView.orientation = "vertical";
|
||||
|
||||
scrollView.width = { value: 200, unit: "px" };
|
||||
scrollView.height = { value: 300, unit: "px" };
|
||||
|
||||
let btn = new button.Button();
|
||||
const btn = new Button();
|
||||
btn.text = "test";
|
||||
btn.width = { value: 500, unit: "px" };
|
||||
btn.height = { value: 500, unit: "px" };
|
||||
@ -31,13 +31,13 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
|
||||
public test_snippets() {
|
||||
// >> article-creating-scrollview
|
||||
var scrollView = new scrollViewModule.ScrollView();
|
||||
const scrollView = new ScrollView();
|
||||
// << article-creating-scrollview
|
||||
TKUnit.assertTrue(scrollView !== null, "ScrollView should be created.");
|
||||
}
|
||||
|
||||
public test_default_TNS_values() {
|
||||
let scroll = new scrollViewModule.ScrollView();
|
||||
const scroll = new ScrollView();
|
||||
TKUnit.assertEqual(scroll.orientation, "vertical", "Default this.testView.orientation");
|
||||
TKUnit.assertEqual(scroll.verticalOffset, 0, "Default this.testView.verticalOffset");
|
||||
TKUnit.assertEqual(scroll.horizontalOffset, 0, "Default this.testView.horizontalOffset");
|
||||
@ -46,22 +46,20 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
public test_vertical_oriantation_creates_correct_native_view() {
|
||||
this.testView.orientation = "vertical";
|
||||
|
||||
if (app.android) {
|
||||
TKUnit.assert(this.testView.android instanceof org.nativescript.widgets.VerticalScrollView, "android property should be instanceof org.nativescript.widgets.VerticalScrollView");
|
||||
}
|
||||
else if (app.ios) {
|
||||
if (isIOS) {
|
||||
TKUnit.assert(this.testView.ios instanceof UIScrollView, "ios property is UIScrollView");
|
||||
} else {
|
||||
TKUnit.assert(this.testView.android instanceof org.nativescript.widgets.VerticalScrollView, "android property should be instanceof org.nativescript.widgets.VerticalScrollView");
|
||||
}
|
||||
}
|
||||
|
||||
public test_horizontal_oriantation_creates_correct_native_view() {
|
||||
this.testView.orientation = "horizontal";
|
||||
|
||||
if (app.android) {
|
||||
TKUnit.assert(this.testView.android instanceof org.nativescript.widgets.HorizontalScrollView, "android property should be instanceof org.nativescript.widgets.HorizontalScrollView");
|
||||
}
|
||||
else if (app.ios) {
|
||||
if (isIOS) {
|
||||
TKUnit.assert(this.testView.ios instanceof UIScrollView, "ios property is UIScrollView");
|
||||
} else {
|
||||
TKUnit.assert(this.testView.android instanceof org.nativescript.widgets.HorizontalScrollView, "android property should be instanceof org.nativescript.widgets.HorizontalScrollView");
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,28 +100,18 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
}
|
||||
|
||||
public test_scrollToVerticalOffset_no_animation() {
|
||||
TKUnit.assertEqual(this.testView.verticalOffset, 0, "this.testView.verticalOffset");
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
// NOTE: when automaticallyAdjustsScrollViewInsets is true (which is the default value)
|
||||
// ScrollView verticalOffset is 20.
|
||||
// TKUnit.assertEqual(this.testView.verticalOffset, 0, "this.testView.verticalOffset");
|
||||
this.testView.scrollToVerticalOffset(layoutHelper.dp(100), false);
|
||||
TKUnit.assertAreClose(layoutHelper.dip(this.testView.verticalOffset), 100, 0.1, "this.testView.verticalOffset");
|
||||
}
|
||||
|
||||
public test_scrollToVerticalOffset_with_animation() {
|
||||
TKUnit.assertEqual(this.testView.verticalOffset, 0, "this.testView.verticalOffset");
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
// NOTE: when automaticallyAdjustsScrollViewInsets is true (which is the default value)
|
||||
// ScrollView verticalOffset is 20.
|
||||
// TKUnit.assertEqual(this.testView.verticalOffset, 0, "this.testView.verticalOffset");
|
||||
this.testView.scrollToVerticalOffset(layoutHelper.dp(100), true);
|
||||
|
||||
// No synchronous change.
|
||||
// NOTE: when automaticallyAdjustsScrollViewInsets is true (which is the default value)
|
||||
// ScrollView verticalOffset is 20.
|
||||
// TKUnit.assertEqual(this.testView.verticalOffset, 0, "this.testView.verticalOffset");
|
||||
|
||||
TKUnit.waitUntilReady(() => { return TKUnit.areClose(layoutHelper.dip(this.testView.verticalOffset), 100, 0.9); });
|
||||
|
||||
// The scrolling animation should be finished by now
|
||||
@ -158,17 +146,15 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
public test_scrollView_persistsState_vertical() {
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
this.testView.scrollToVerticalOffset(layoutHelper.dp(100), false);
|
||||
TKUnit.assertAreClose(layoutHelper.dip(this.testView.verticalOffset), 100, 0.1, "this.testView.verticalOffset before navigation");
|
||||
const expected = layoutHelper.dp(100);
|
||||
this.testView.scrollToVerticalOffset(expected, false);
|
||||
// TKUnit.assertAreClose(this.testView.verticalOffset, expected, 0.1, "this.testView.verticalOffset before navigation");
|
||||
|
||||
helper.navigateWithHistory(() => new Page());
|
||||
helper.goBack();
|
||||
|
||||
// Wait for the page to reload.
|
||||
TKUnit.waitUntilReady(() => { return TKUnit.areClose(layoutHelper.dip(this.testView.verticalOffset), 100, 0.1); });
|
||||
|
||||
// Check verticalOffset after navigation
|
||||
TKUnit.assertAreClose(layoutHelper.dip(this.testView.verticalOffset), 100, 0.1, "this.testView.verticalOffset after navigation");
|
||||
TKUnit.assertAreClose(this.testView.verticalOffset, expected, 0.1, "this.testView.verticalOffset after navigation");
|
||||
}
|
||||
|
||||
public test_scrollView_persistsState_horizontal() {
|
||||
@ -178,16 +164,17 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.testView.scrollToHorizontalOffset(layoutHelper.dp(100), false);
|
||||
|
||||
TKUnit.assertAreClose(layoutHelper.dip(this.testView.horizontalOffset), 100, 0.1, "this.testView.horizontalOffset before navigation");
|
||||
|
||||
helper.navigateWithHistory(() => new Page());
|
||||
helper.goBack();
|
||||
|
||||
// Check verticalOffset after navigation
|
||||
// Check horizontalOffset after navigation
|
||||
TKUnit.assertAreClose(layoutHelper.dip(this.testView.horizontalOffset), 100, 0.1, "this.testView.horizontalOffset after navigation");
|
||||
}
|
||||
|
||||
public test_scrollView_vertical_raised_scroll_event() {
|
||||
var scrollY: number;
|
||||
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
|
||||
this.testView.on(ScrollView.scrollEvent, (args: ScrollEventData) => {
|
||||
scrollY = args.scrollY;
|
||||
});
|
||||
|
||||
@ -202,7 +189,7 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.testView.orientation = "horizontal";
|
||||
|
||||
var scrollX: number;
|
||||
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
|
||||
this.testView.on(ScrollView.scrollEvent, (args: ScrollEventData) => {
|
||||
scrollX = args.scrollX;
|
||||
});
|
||||
|
||||
@ -217,7 +204,7 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
var scrollY: number;
|
||||
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
|
||||
this.testView.on(ScrollView.scrollEvent, (args: ScrollEventData) => {
|
||||
scrollY = args.scrollY;
|
||||
});
|
||||
|
||||
@ -232,7 +219,7 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
var scrollX: number;
|
||||
this.testView.on(scrollViewModule.ScrollView.scrollEvent, (args: scrollViewModule.ScrollEventData) => {
|
||||
this.testView.on(ScrollView.scrollEvent, (args: ScrollEventData) => {
|
||||
scrollX = args.scrollX;
|
||||
});
|
||||
|
||||
@ -249,7 +236,7 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.testView.scrollBarIndicatorVisible = true;
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
if (app.ios) {
|
||||
if (isIOS) {
|
||||
TKUnit.assertEqual(this.testView.ios.showsHorizontalScrollIndicator, true);
|
||||
} else {
|
||||
TKUnit.assertEqual(this.testView.android.isHorizontalScrollBarEnabled(), true);
|
||||
@ -258,7 +245,7 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.testView.scrollBarIndicatorVisible = false;
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
if (app.ios) {
|
||||
if (isIOS) {
|
||||
TKUnit.assertEqual(this.testView.ios.showsHorizontalScrollIndicator, false);
|
||||
} else {
|
||||
TKUnit.assertEqual(this.testView.android.isHorizontalScrollBarEnabled(), false);
|
||||
@ -270,7 +257,7 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.testView.scrollBarIndicatorVisible = true;
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
if (app.ios) {
|
||||
if (isIOS) {
|
||||
TKUnit.assertEqual(this.testView.ios.showsVerticalScrollIndicator, true);
|
||||
} else {
|
||||
TKUnit.assertEqual(this.testView.android.isVerticalScrollBarEnabled(), true);
|
||||
@ -279,7 +266,7 @@ class ScrollLayoutTest extends testModule.UITest<scrollViewModule.ScrollView> {
|
||||
this.testView.scrollBarIndicatorVisible = false;
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
if (app.ios) {
|
||||
if (isIOS) {
|
||||
TKUnit.assertEqual(this.testView.ios.showsVerticalScrollIndicator, false);
|
||||
} else {
|
||||
TKUnit.assertEqual(this.testView.android.isVerticalScrollBarEnabled(), false);
|
||||
|
@ -246,7 +246,7 @@ function _clickTheFirstButtonInTheListViewNatively(tabView: TabView) {
|
||||
button.performClick();
|
||||
}
|
||||
else {
|
||||
const tableView = <UITableView>tabView.ios.viewControllers[0].view;
|
||||
const tableView = <UITableView>tabView.ios.selectedViewController.view.subviews[0];
|
||||
const cell = <UITableViewCell>tableView.cellForRowAtIndexPath(NSIndexPath.indexPathForItemInSection(0, 0));
|
||||
const btn = <UIButton>cell.contentView.subviews[0];
|
||||
btn.sendActionsForControlEvents(UIControlEvents.TouchUpInside);
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
// First reexport so that app module is initialized.
|
||||
export * from "./application-common";
|
||||
|
||||
import { ios as iosView } from "../ui/core/view";
|
||||
import { ios as iosView, ViewBase } from "../ui/core/view";
|
||||
import { Frame, View, NavigationEntry, loadViewFromEntry } from "../ui/frame";
|
||||
import { ios } from "../ui/utils";
|
||||
import * as utils from "../utils/utils";
|
||||
@ -49,6 +49,7 @@ class IOSApplication implements IOSApplicationDefinition {
|
||||
private _currentOrientation = utils.ios.getter(UIDevice, UIDevice.currentDevice).orientation;
|
||||
private _window: UIWindow;
|
||||
private _observers: Array<NotificationObserver>;
|
||||
private _rootView: ViewBase;
|
||||
|
||||
constructor() {
|
||||
this._observers = new Array<NotificationObserver>();
|
||||
@ -112,6 +113,7 @@ class IOSApplication implements IOSApplicationDefinition {
|
||||
notify(<LoadAppCSSEventData>{ eventName: "loadAppCss", object: <any>this, cssFile: getCssFileName() });
|
||||
|
||||
const rootView = createRootView(args.root);
|
||||
this._rootView = rootView;
|
||||
const controller = getViewController(rootView);
|
||||
this._window.rootViewController = controller;
|
||||
this._window.makeKeyAndVisible();
|
||||
@ -238,12 +240,12 @@ export function getNativeApplication(): UIApplication {
|
||||
}
|
||||
|
||||
function getViewController(view: View): UIViewController {
|
||||
let viewController = view.viewController || view.ios;
|
||||
let viewController: UIViewController = view.viewController || view.ios;
|
||||
if (viewController instanceof UIViewController) {
|
||||
return viewController;
|
||||
} else if (view.ios instanceof UIView) {
|
||||
viewController = iosView.UILayoutViewController.initWithOwner(new WeakRef(view));
|
||||
viewController.view = view.ios;
|
||||
viewController.view.addSubview(view.ios);
|
||||
return viewController;
|
||||
} else {
|
||||
throw new Error("Root should be either UIViewController or UIView");
|
||||
|
@ -43,11 +43,7 @@ export class ContentView extends CustomLayoutView implements ContentViewDefiniti
|
||||
}
|
||||
|
||||
get _childrenCount(): number {
|
||||
if (this._content) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return this._content ? 1 : 0;
|
||||
}
|
||||
|
||||
public _onContentChanged(oldView: View, newView: View) {
|
||||
|
@ -122,6 +122,10 @@ export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<
|
||||
const changed: boolean = equalityComparer ? !equalityComparer(oldValue, value) : oldValue !== value;
|
||||
|
||||
if (wrapped || changed) {
|
||||
if (affectsLayout) {
|
||||
this.requestLayout();
|
||||
}
|
||||
|
||||
if (reset) {
|
||||
delete this[key];
|
||||
if (valueChanged) {
|
||||
@ -164,10 +168,6 @@ export class Property<T extends ViewBase, U> implements TypedPropertyDescriptor<
|
||||
this.notify<PropertyChangeData>({ object: this, eventName, propertyName, value, oldValue });
|
||||
}
|
||||
|
||||
if (affectsLayout) {
|
||||
this.requestLayout();
|
||||
}
|
||||
|
||||
if (this.domNode) {
|
||||
if (reset) {
|
||||
this.domNode.attributeRemoved(propertyName);
|
||||
|
@ -487,7 +487,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
return curState | newState;
|
||||
}
|
||||
|
||||
public static layoutChild(parent: ViewDefinition, child: ViewDefinition, left: number, top: number, right: number, bottom: number): void {
|
||||
public static layoutChild(parent: ViewDefinition, child: ViewDefinition, left: number, top: number, right: number, bottom: number, setFrame: boolean = true): void {
|
||||
if (!child || child.isCollapsed) {
|
||||
return;
|
||||
}
|
||||
@ -571,7 +571,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
traceWrite(child.parent + " :layoutChild: " + child + " " + childLeft + ", " + childTop + ", " + childRight + ", " + childBottom, traceCategories.Layout);
|
||||
}
|
||||
|
||||
child.layout(childLeft, childTop, childRight, childBottom);
|
||||
child.layout(childLeft, childTop, childRight, childBottom, setFrame);
|
||||
}
|
||||
|
||||
public static measureChild(parent: ViewCommon, child: ViewCommon, widthMeasureSpec: number, heightMeasureSpec: number): { measuredWidth: number; measuredHeight: number } {
|
||||
@ -579,17 +579,27 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
let measureHeight = 0;
|
||||
|
||||
if (child && !child.isCollapsed) {
|
||||
child._updateEffectiveLayoutValues(parent);
|
||||
|
||||
let style = child.style;
|
||||
let horizontalMargins = child.effectiveMarginLeft + child.effectiveMarginRight;
|
||||
let verticalMargins = child.effectiveMarginTop + child.effectiveMarginBottom;
|
||||
const widthSpec = parent ? parent._currentWidthMeasureSpec : widthMeasureSpec;
|
||||
const heightSpec = parent ? parent._currentHeightMeasureSpec : heightMeasureSpec;
|
||||
|
||||
let childWidthMeasureSpec = ViewCommon.getMeasureSpec(widthMeasureSpec, horizontalMargins, child.effectiveWidth, style.horizontalAlignment === "stretch");
|
||||
let childHeightMeasureSpec = ViewCommon.getMeasureSpec(heightMeasureSpec, verticalMargins, child.effectiveHeight, style.verticalAlignment === "stretch");
|
||||
const width = layout.getMeasureSpecSize(widthSpec);
|
||||
const widthMode = layout.getMeasureSpecMode(widthSpec);
|
||||
|
||||
const height = layout.getMeasureSpecSize(heightSpec);
|
||||
const heightMode = layout.getMeasureSpecMode(heightSpec);
|
||||
|
||||
child._updateEffectiveLayoutValues(width, widthMode, height, heightMode);
|
||||
|
||||
const style = child.style;
|
||||
const horizontalMargins = child.effectiveMarginLeft + child.effectiveMarginRight;
|
||||
const verticalMargins = child.effectiveMarginTop + child.effectiveMarginBottom;
|
||||
|
||||
const childWidthMeasureSpec = ViewCommon.getMeasureSpec(widthMeasureSpec, horizontalMargins, child.effectiveWidth, style.horizontalAlignment === "stretch");
|
||||
const childHeightMeasureSpec = ViewCommon.getMeasureSpec(heightMeasureSpec, verticalMargins, child.effectiveHeight, style.verticalAlignment === "stretch");
|
||||
|
||||
if (traceEnabled()) {
|
||||
traceWrite(child.parent + " :measureChild: " + child + " " + layout.measureSpecToString(childWidthMeasureSpec) + ", " + layout.measureSpecToString(childHeightMeasureSpec), traceCategories.Layout);
|
||||
traceWrite(`${child.parent} :measureChild: ${child} ${layout.measureSpecToString(childWidthMeasureSpec)}, ${layout.measureSpecToString(childHeightMeasureSpec)}}`, traceCategories.Layout);
|
||||
}
|
||||
|
||||
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
|
||||
@ -760,26 +770,24 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
throw new Error("The View._setValue is obsolete. There is a new property system.");
|
||||
}
|
||||
|
||||
_updateEffectiveLayoutValues(parent: ViewDefinition): void {
|
||||
_updateEffectiveLayoutValues(
|
||||
parentWidthMeasureSize: number,
|
||||
parentWidthMeasureMode: number,
|
||||
parentHeightMeasureSize: number,
|
||||
parentHeightMeasureMode: number): void {
|
||||
const style = this.style;
|
||||
|
||||
let parentWidthMeasureSpec = parent._currentWidthMeasureSpec;
|
||||
let parentWidthMeasureSize = layout.getMeasureSpecSize(parentWidthMeasureSpec);
|
||||
let parentWidthMeasureMode = layout.getMeasureSpecMode(parentWidthMeasureSpec);
|
||||
let parentAvailableWidth = parentWidthMeasureMode === layout.UNSPECIFIED ? -1 : parentWidthMeasureSize;
|
||||
const availableWidth = parentWidthMeasureMode === layout.UNSPECIFIED ? -1 : parentWidthMeasureSize;
|
||||
|
||||
this.effectiveWidth = PercentLength.toDevicePixels(style.width, -2, parentAvailableWidth);
|
||||
this.effectiveMarginLeft = PercentLength.toDevicePixels(style.marginLeft, 0, parentAvailableWidth);
|
||||
this.effectiveMarginRight = PercentLength.toDevicePixels(style.marginRight, 0, parentAvailableWidth);
|
||||
this.effectiveWidth = PercentLength.toDevicePixels(style.width, -2, availableWidth);
|
||||
this.effectiveMarginLeft = PercentLength.toDevicePixels(style.marginLeft, 0, availableWidth);
|
||||
this.effectiveMarginRight = PercentLength.toDevicePixels(style.marginRight, 0, availableWidth);
|
||||
|
||||
let parentHeightMeasureSpec = parent._currentHeightMeasureSpec;
|
||||
let parentHeightMeasureSize = layout.getMeasureSpecSize(parentHeightMeasureSpec);
|
||||
let parentHeightMeasureMode = layout.getMeasureSpecMode(parentHeightMeasureSpec);
|
||||
let parentAvailableHeight = parentHeightMeasureMode === layout.UNSPECIFIED ? -1 : parentHeightMeasureSize;
|
||||
const availableHeight = parentHeightMeasureMode === layout.UNSPECIFIED ? -1 : parentHeightMeasureSize;
|
||||
|
||||
this.effectiveHeight = PercentLength.toDevicePixels(style.height, -2, parentAvailableHeight);
|
||||
this.effectiveMarginTop = PercentLength.toDevicePixels(style.marginTop, 0, parentAvailableHeight);
|
||||
this.effectiveMarginBottom = PercentLength.toDevicePixels(style.marginBottom, 0, parentAvailableHeight);
|
||||
this.effectiveHeight = PercentLength.toDevicePixels(style.height, -2, availableHeight);
|
||||
this.effectiveMarginTop = PercentLength.toDevicePixels(style.marginTop, 0, availableHeight);
|
||||
this.effectiveMarginBottom = PercentLength.toDevicePixels(style.marginBottom, 0, availableHeight);
|
||||
}
|
||||
|
||||
public _setNativeClipToBounds() {
|
||||
|
7
tns-core-modules/ui/core/view/view.d.ts
vendored
7
tns-core-modules/ui/core/view/view.d.ts
vendored
@ -524,7 +524,11 @@ export abstract class View extends ViewBase {
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_updateEffectiveLayoutValues(parent: View): void;
|
||||
_updateEffectiveLayoutValues(
|
||||
parentWidthMeasureSize: number,
|
||||
parentWidthMeasureMode: number,
|
||||
parentHeightMeasureSize: number,
|
||||
parentHeightMeasureMode: number): void
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@ -641,6 +645,7 @@ export const isEnabledProperty: Property<View, boolean>;
|
||||
export const isUserInteractionEnabledProperty: Property<View, boolean>;
|
||||
|
||||
export namespace ios {
|
||||
export function updateConstraints(controller: UIViewController, owner: View): void;
|
||||
export function layoutView(controller: UIViewController, owner: View): void;
|
||||
export class UILayoutViewController extends UIViewController {
|
||||
public static initWithOwner(owner: WeakRef<View>): UILayoutViewController;
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Definitions.
|
||||
import { Point, View as ViewDefinition, dip } from ".";
|
||||
import { ViewBase } from "../view-base";
|
||||
|
||||
import {
|
||||
ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty,
|
||||
@ -39,10 +40,6 @@ export class View extends ViewCommon {
|
||||
*/
|
||||
_nativeBackgroundState: "unset" | "invalid" | "drawn";
|
||||
|
||||
// get nativeView(): UIView {
|
||||
// return this.ios;
|
||||
// }
|
||||
|
||||
public _addViewCore(view: ViewCommon, atIndex?: number) {
|
||||
super._addViewCore(view, atIndex);
|
||||
this.requestLayout();
|
||||
@ -67,13 +64,11 @@ export class View extends ViewCommon {
|
||||
|
||||
const parent = <View>this.parent;
|
||||
if (parent) {
|
||||
if (!parent.isLayoutRequested) {
|
||||
parent.requestLayout();
|
||||
}
|
||||
parent.requestLayout();
|
||||
}
|
||||
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (nativeView && this.isLoaded) {
|
||||
if (nativeView) {
|
||||
nativeView.setNeedsLayout();
|
||||
}
|
||||
}
|
||||
@ -82,7 +77,6 @@ export class View extends ViewCommon {
|
||||
let measureSpecsChanged = this._setCurrentMeasureSpecs(widthMeasureSpec, heightMeasureSpec);
|
||||
let forceLayout = (this._privateFlags & PFLAG_FORCE_LAYOUT) === PFLAG_FORCE_LAYOUT;
|
||||
if (forceLayout || measureSpecsChanged) {
|
||||
|
||||
// first clears the measured dimension flag
|
||||
this._privateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
|
||||
|
||||
@ -100,7 +94,7 @@ export class View extends ViewCommon {
|
||||
|
||||
@profile
|
||||
public layout(left: number, top: number, right: number, bottom: number, setFrame = true): void {
|
||||
let { boundsChanged, sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom);
|
||||
const { boundsChanged, sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom);
|
||||
if (setFrame) {
|
||||
this.layoutNativeView(left, top, right, bottom);
|
||||
}
|
||||
@ -110,14 +104,17 @@ export class View extends ViewCommon {
|
||||
this._privateFlags &= ~PFLAG_LAYOUT_REQUIRED;
|
||||
}
|
||||
|
||||
this.updateBackground(sizeChanged);
|
||||
this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
|
||||
}
|
||||
|
||||
private updateBackground(sizeChanged: boolean): void {
|
||||
if (sizeChanged) {
|
||||
this._onSizeChanged();
|
||||
} else if (this._nativeBackgroundState === "invalid") {
|
||||
let background = this.style.backgroundInternal;
|
||||
const background = this.style.backgroundInternal;
|
||||
this._redrawNativeBackground(background);
|
||||
}
|
||||
|
||||
this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
|
||||
}
|
||||
|
||||
public setMeasuredDimension(measuredWidth: number, measuredHeight: number): void {
|
||||
@ -163,7 +160,7 @@ export class View extends ViewCommon {
|
||||
this._cachedFrame = frame;
|
||||
if (this._hasTransfrom) {
|
||||
// Always set identity transform before setting frame;
|
||||
let transform = nativeView.transform;
|
||||
const transform = nativeView.transform;
|
||||
nativeView.transform = CGAffineTransformIdentity;
|
||||
nativeView.frame = frame;
|
||||
nativeView.transform = transform;
|
||||
@ -171,7 +168,8 @@ export class View extends ViewCommon {
|
||||
else {
|
||||
nativeView.frame = frame;
|
||||
}
|
||||
let boundsOrigin = nativeView.bounds.origin;
|
||||
|
||||
const boundsOrigin = nativeView.bounds.origin;
|
||||
nativeView.bounds = CGRectMake(boundsOrigin.x, boundsOrigin.y, frame.size.width, frame.size.height);
|
||||
}
|
||||
}
|
||||
@ -186,6 +184,22 @@ export class View extends ViewCommon {
|
||||
this._setNativeViewFrame(nativeView, frame);
|
||||
}
|
||||
|
||||
public _setLayoutFlags(left: number, top: number, right: number, bottom: number): void {
|
||||
const width = right - left;
|
||||
const height = bottom - top;
|
||||
const widthSpec = layout.makeMeasureSpec(width, layout.EXACTLY);
|
||||
const heightSpec = layout.makeMeasureSpec(height, layout.EXACTLY);
|
||||
this._setCurrentMeasureSpecs(widthSpec, heightSpec);
|
||||
this._privateFlags &= ~PFLAG_FORCE_LAYOUT;
|
||||
this.setMeasuredDimension(width, height);
|
||||
|
||||
const { sizeChanged } = this._setCurrentLayoutBounds(left, top, right, bottom);
|
||||
this.updateBackground(sizeChanged);
|
||||
this._privateFlags &= ~PFLAG_LAYOUT_REQUIRED;
|
||||
// NOTE: if there is transformation this frame will be incorrect.
|
||||
this._cachedFrame = this.nativeViewProtected.frame;
|
||||
}
|
||||
|
||||
public focus(): boolean {
|
||||
if (this.ios) {
|
||||
return this.ios.becomeFirstResponder();
|
||||
@ -199,7 +213,7 @@ export class View extends ViewCommon {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
|
||||
const pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
|
||||
return {
|
||||
x: pointInWindow.x,
|
||||
y: pointInWindow.y
|
||||
@ -211,8 +225,8 @@ export class View extends ViewCommon {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
|
||||
let pointOnScreen = this.nativeViewProtected.window.convertPointToWindow(pointInWindow, null);
|
||||
const pointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
|
||||
const pointOnScreen = this.nativeViewProtected.window.convertPointToWindow(pointInWindow, null);
|
||||
return {
|
||||
x: pointOnScreen.x,
|
||||
y: pointOnScreen.y
|
||||
@ -226,8 +240,8 @@ export class View extends ViewCommon {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let myPointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
|
||||
let otherPointInWindow = otherView.nativeViewProtected.convertPointToView(otherView.nativeViewProtected.bounds.origin, null);
|
||||
const myPointInWindow = this.nativeViewProtected.convertPointToView(this.nativeViewProtected.bounds.origin, null);
|
||||
const otherPointInWindow = otherView.nativeViewProtected.convertPointToView(otherView.nativeViewProtected.bounds.origin, null);
|
||||
return {
|
||||
x: myPointInWindow.x - otherPointInWindow.x,
|
||||
y: myPointInWindow.y - otherPointInWindow.y
|
||||
@ -256,15 +270,15 @@ export class View extends ViewCommon {
|
||||
}
|
||||
|
||||
public updateNativeTransform() {
|
||||
let scaleX = this.scaleX || 1e-6;
|
||||
let scaleY = this.scaleY || 1e-6;
|
||||
let rotate = this.rotate || 0;
|
||||
const scaleX = this.scaleX || 1e-6;
|
||||
const scaleY = this.scaleY || 1e-6;
|
||||
const rotate = this.rotate || 0;
|
||||
let newTransform = CGAffineTransformIdentity;
|
||||
newTransform = CGAffineTransformTranslate(newTransform, this.translateX, this.translateY);
|
||||
newTransform = CGAffineTransformRotate(newTransform, rotate * Math.PI / 180);
|
||||
newTransform = CGAffineTransformScale(newTransform, scaleX, scaleY);
|
||||
if (!CGAffineTransformEqualToTransform(this.nativeViewProtected.transform, newTransform)) {
|
||||
let updateSuspended = this._isPresentationLayerUpdateSuspeneded();
|
||||
const updateSuspended = this._isPresentationLayerUpdateSuspeneded();
|
||||
if (!updateSuspended) {
|
||||
CATransaction.begin();
|
||||
}
|
||||
@ -277,7 +291,7 @@ export class View extends ViewCommon {
|
||||
}
|
||||
|
||||
public updateOriginPoint(originX: number, originY: number) {
|
||||
let newPoint = CGPointMake(originX, originY);
|
||||
const newPoint = CGPointMake(originX, originY);
|
||||
this.nativeViewProtected.layer.anchorPoint = newPoint;
|
||||
if (this._cachedFrame) {
|
||||
this._setNativeViewFrame(this.nativeViewProtected, this._cachedFrame);
|
||||
@ -300,11 +314,11 @@ export class View extends ViewCommon {
|
||||
}
|
||||
|
||||
[isEnabledProperty.getDefault](): boolean {
|
||||
let nativeView = this.nativeViewProtected;
|
||||
const nativeView = this.nativeViewProtected;
|
||||
return nativeView instanceof UIControl ? nativeView.enabled : true;
|
||||
}
|
||||
[isEnabledProperty.setNative](value: boolean) {
|
||||
let nativeView = this.nativeViewProtected;
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (nativeView instanceof UIControl) {
|
||||
nativeView.enabled = value;
|
||||
}
|
||||
@ -446,7 +460,7 @@ export class View extends ViewCommon {
|
||||
}
|
||||
|
||||
_setNativeClipToBounds() {
|
||||
let backgroundInternal = this.style.backgroundInternal;
|
||||
const backgroundInternal = this.style.backgroundInternal;
|
||||
this.nativeViewProtected.clipsToBounds =
|
||||
this.nativeViewProtected instanceof UIScrollView ||
|
||||
backgroundInternal.hasBorderWidth() ||
|
||||
@ -461,7 +475,7 @@ export class CustomLayoutView extends View {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.nativeViewProtected = UIView.new();
|
||||
this.nativeViewProtected = UIView.alloc().initWithFrame(iosUtils.getter(UIScreen, UIScreen.mainScreen).bounds);
|
||||
}
|
||||
|
||||
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
||||
@ -494,23 +508,36 @@ export class CustomLayoutView extends View {
|
||||
child.nativeViewProtected.removeFromSuperview();
|
||||
}
|
||||
}
|
||||
|
||||
_getCurrentLayoutBounds(): { left: number; top: number; right: number; bottom: number } {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (nativeView && !this.isCollapsed) {
|
||||
const frame = nativeView.frame;
|
||||
const origin = frame.origin;
|
||||
const size = frame.size;
|
||||
return {
|
||||
left: layout.toDevicePixels(origin.x),
|
||||
top: layout.toDevicePixels(origin.y),
|
||||
right: layout.toDevicePixels(origin.x + size.width),
|
||||
bottom: layout.toDevicePixels(origin.y + size.height)
|
||||
};
|
||||
} else {
|
||||
return { left: 0, top: 0, right: 0, bottom: 0 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isScrollable(controller: UIViewController, owner: View): boolean {
|
||||
let scrollable = (<any>owner).scrollableContent;
|
||||
if (scrollable === undefined) {
|
||||
if (controller.childViewControllers.count > 0) {
|
||||
scrollable = true;
|
||||
} else {
|
||||
let view = controller.view;
|
||||
while (view) {
|
||||
if (view instanceof UIScrollView) {
|
||||
scrollable = true;
|
||||
break;
|
||||
}
|
||||
|
||||
view = view.subviews.count > 0 ? view.subviews[0] : null;
|
||||
let view = controller.view;
|
||||
while (view) {
|
||||
if (view instanceof UIScrollView) {
|
||||
scrollable = true;
|
||||
break;
|
||||
}
|
||||
|
||||
view = view.subviews.count > 0 ? view.subviews[0] : null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,66 +557,157 @@ function getStatusBarHeight(controller: UIViewController): number {
|
||||
return shouldReturnStatusBarHeight ? uiUtils.ios.getStatusBarHeight(controller) : 0;
|
||||
}
|
||||
|
||||
const majorVersion = iosUtils.MajorVersion;
|
||||
|
||||
interface ExtendedController extends UIViewController {
|
||||
scrollable: boolean;
|
||||
navBarHidden: boolean;
|
||||
hasChildControllers: boolean;
|
||||
|
||||
safeAreaLeft: NSLayoutConstraint;
|
||||
safeAreaTop: NSLayoutConstraint;
|
||||
safeAreaRight: NSLayoutConstraint;
|
||||
safeAreaBottom: NSLayoutConstraint;
|
||||
fullscreenTop: NSLayoutConstraint;
|
||||
fullscreenBottom: NSLayoutConstraint;
|
||||
activeConstraints: NSLayoutConstraint[];
|
||||
}
|
||||
|
||||
export namespace ios {
|
||||
export function layoutView(controller: UIViewController, owner: View): void {
|
||||
const scrollableContent = isScrollable(controller, owner);
|
||||
function constrainView(controller: UIViewController, owner: View): void {
|
||||
const root = controller.view;
|
||||
const view = root.subviews[0];
|
||||
const extendedController = <ExtendedController>controller;
|
||||
|
||||
if (!extendedController.safeAreaTop) {
|
||||
view.translatesAutoresizingMaskIntoConstraints = false;
|
||||
if (majorVersion > 10) {
|
||||
const safeArea = root.safeAreaLayoutGuide;
|
||||
extendedController.safeAreaTop = view.topAnchor.constraintEqualToAnchor(safeArea.topAnchor);
|
||||
extendedController.fullscreenTop = view.topAnchor.constraintEqualToAnchor(root.topAnchor);
|
||||
extendedController.safeAreaBottom = view.bottomAnchor.constraintEqualToAnchor(safeArea.bottomAnchor);
|
||||
extendedController.fullscreenBottom = view.bottomAnchor.constraintEqualToAnchor(root.bottomAnchor);
|
||||
extendedController.safeAreaLeft = view.leftAnchor.constraintEqualToAnchor(safeArea.leftAnchor);
|
||||
extendedController.safeAreaRight = view.rightAnchor.constraintEqualToAnchor(safeArea.rightAnchor);
|
||||
} else {
|
||||
extendedController.safeAreaTop = view.topAnchor.constraintEqualToAnchor(controller.topLayoutGuide.bottomAnchor);
|
||||
extendedController.fullscreenTop = view.topAnchor.constraintEqualToAnchor(root.topAnchor);
|
||||
extendedController.safeAreaBottom = view.bottomAnchor.constraintEqualToAnchor(controller.bottomLayoutGuide.topAnchor);
|
||||
extendedController.fullscreenBottom = view.bottomAnchor.constraintEqualToAnchor(root.bottomAnchor);
|
||||
extendedController.safeAreaLeft = view.leadingAnchor.constraintEqualToAnchor(root.leadingAnchor);
|
||||
extendedController.safeAreaRight = view.trailingAnchor.constraintEqualToAnchor(root.trailingAnchor);
|
||||
}
|
||||
}
|
||||
|
||||
const navController = controller.navigationController;
|
||||
const navBarVisible = navController && !navController.navigationBarHidden;
|
||||
const navBarTranslucent = navController ? navController.navigationBar.translucent : false;
|
||||
const navBarHidden = navController ? navController.navigationBarHidden : true;
|
||||
const scrollable = (owner && isScrollable(controller, owner));
|
||||
const hasChildControllers = controller.childViewControllers.count > 0;
|
||||
const constraints = [
|
||||
hasChildControllers || scrollable ? extendedController.fullscreenBottom : extendedController.safeAreaBottom,
|
||||
extendedController.safeAreaLeft,
|
||||
extendedController.safeAreaRight
|
||||
];
|
||||
|
||||
let navBarHeight = navBarVisible ? uiUtils.ios.getActualHeight(navController.navigationBar) : 0;
|
||||
let statusBarHeight = getStatusBarHeight(controller);
|
||||
|
||||
const edgesForExtendedLayout = controller.edgesForExtendedLayout;
|
||||
const extendedLayoutIncludesOpaqueBars = controller.extendedLayoutIncludesOpaqueBars;
|
||||
const layoutExtendsOnTop = (edgesForExtendedLayout & UIRectEdge.Top) === UIRectEdge.Top;
|
||||
if (!layoutExtendsOnTop
|
||||
|| (!extendedLayoutIncludesOpaqueBars && !navBarTranslucent && navBarVisible)
|
||||
|| (scrollableContent && navBarVisible)) {
|
||||
navBarHeight = 0;
|
||||
statusBarHeight = 0;
|
||||
if (hasChildControllers) {
|
||||
// If not inner most extend to fullscreen
|
||||
constraints.push(extendedController.fullscreenTop);
|
||||
} else if (!scrollable) {
|
||||
// If not scrollable dock under safe area
|
||||
constraints.push(extendedController.safeAreaTop);
|
||||
} else if (navBarHidden) {
|
||||
// If scrollable but no navigation bar dock under safe area
|
||||
constraints.push(extendedController.safeAreaTop);
|
||||
} else {
|
||||
// If scrollable and navigation bar extend to fullscreen
|
||||
constraints.push(extendedController.fullscreenTop);
|
||||
}
|
||||
|
||||
const tabBarController = controller.tabBarController;
|
||||
const layoutExtendsOnBottom = (edgesForExtendedLayout & UIRectEdge.Bottom) === UIRectEdge.Bottom;
|
||||
const activeConstraints = extendedController.activeConstraints;
|
||||
if (activeConstraints) {
|
||||
NSLayoutConstraint.deactivateConstraints(<any>activeConstraints);
|
||||
}
|
||||
NSLayoutConstraint.activateConstraints(<any>constraints);
|
||||
|
||||
let tabBarHeight = 0;
|
||||
const tabBarVisible = tabBarController && !tabBarController.tabBar.hidden;
|
||||
const tabBarTranslucent = tabBarController ? tabBarController.tabBar.translucent : false;
|
||||
extendedController.scrollable = scrollable;
|
||||
extendedController.navBarHidden = navBarHidden;
|
||||
extendedController.hasChildControllers = hasChildControllers;
|
||||
extendedController.activeConstraints = constraints;
|
||||
}
|
||||
|
||||
// If tabBar is visible and we don't have scrollableContent and layout
|
||||
// goes under tabBar we need to reduce available height with tabBar height
|
||||
if (tabBarVisible && !scrollableContent && layoutExtendsOnBottom && (tabBarTranslucent || extendedLayoutIncludesOpaqueBars)) {
|
||||
tabBarHeight = tabBarController.tabBar.frame.size.height;
|
||||
export function updateConstraints(controller: UIViewController, owner: View): void {
|
||||
const extendedController = <ExtendedController>controller;
|
||||
const navController = controller.navigationController;
|
||||
const navBarHidden = navController ? navController.navigationBarHidden : true;
|
||||
const scrollable = (owner && isScrollable(controller, owner));
|
||||
const hasChildControllers = controller.childViewControllers.count > 0;
|
||||
|
||||
if (extendedController.scrollable !== scrollable
|
||||
|| extendedController.navBarHidden !== navBarHidden
|
||||
|| extendedController.hasChildControllers !== hasChildControllers) {
|
||||
constrainView(extendedController, owner);
|
||||
}
|
||||
}
|
||||
|
||||
export function layoutView(controller: UIViewController, owner: View): void {
|
||||
// If we are not last controller - don't
|
||||
if (controller.childViewControllers.count > 0) {// || controller.view !== owner.nativeView.superview) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size = controller.view.bounds.size;
|
||||
const frame = controller.beingPresented ? owner.nativeView.superview.frame : controller.view.subviews[0].bounds;
|
||||
const origin = frame.origin;
|
||||
const size = frame.size;
|
||||
const width = layout.toDevicePixels(size.width);
|
||||
const height = layout.toDevicePixels(size.height - tabBarHeight);
|
||||
const height = layout.toDevicePixels(size.height);
|
||||
|
||||
const widthSpec = layout.makeMeasureSpec(width, layout.EXACTLY);
|
||||
const heightSpec = layout.makeMeasureSpec(height - statusBarHeight - navBarHeight, layout.EXACTLY);
|
||||
const heightSpec = layout.makeMeasureSpec(height, layout.EXACTLY);
|
||||
|
||||
owner.measure(widthSpec, heightSpec);
|
||||
View.measureChild(null, owner, widthSpec, heightSpec);
|
||||
const left = layout.toDevicePixels(origin.x);
|
||||
const top = layout.toDevicePixels(origin.y);
|
||||
View.layoutChild(null, owner, left, top, width + left, height + top, false);
|
||||
|
||||
// Page.nativeView.frame is never set by our layout...
|
||||
owner.layout(0, statusBarHeight + navBarHeight, width, height, false);
|
||||
layoutParent(owner.parent);
|
||||
}
|
||||
|
||||
function layoutParent(view: ViewBase): void {
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (view instanceof View) {
|
||||
const frame = view.nativeViewProtected.frame;
|
||||
const origin = frame.origin;
|
||||
const size = frame.size;
|
||||
const left = layout.toDevicePixels(origin.x);
|
||||
const top = layout.toDevicePixels(origin.y);
|
||||
const width = layout.toDevicePixels(size.width);
|
||||
const height = layout.toDevicePixels(size.height);
|
||||
view._setLayoutFlags(left, top, width + left, height + top);
|
||||
}
|
||||
|
||||
layoutParent(view.parent);
|
||||
}
|
||||
|
||||
export class UILayoutViewController extends UIViewController {
|
||||
public owner: WeakRef<View>;
|
||||
|
||||
|
||||
public static initWithOwner(owner: WeakRef<View>): UILayoutViewController {
|
||||
const controller = <UILayoutViewController>UILayoutViewController.new();
|
||||
controller.owner = owner;
|
||||
return controller;
|
||||
}
|
||||
|
||||
public viewWillLayoutSubviews(): void {
|
||||
super.viewWillLayoutSubviews();
|
||||
updateConstraints(this, this.owner.get())
|
||||
}
|
||||
|
||||
public viewDidLayoutSubviews(): void {
|
||||
super.viewDidLayoutSubviews();
|
||||
|
||||
const owner = this.owner.get();
|
||||
layoutView(this, owner);
|
||||
layoutView(this, this.owner.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +228,19 @@ export class Frame extends FrameBase {
|
||||
FrameBase.defaultTransition = value;
|
||||
}
|
||||
|
||||
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
||||
const width = layout.getMeasureSpecSize(widthMeasureSpec);
|
||||
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
|
||||
|
||||
const height = layout.getMeasureSpecSize(heightMeasureSpec);
|
||||
const heightMode = layout.getMeasureSpecMode(heightMeasureSpec);
|
||||
|
||||
const widthAndState = View.resolveSizeAndState(width, width, widthMode, 0);
|
||||
const heightAndState = View.resolveSizeAndState(height, height, heightMode, 0);
|
||||
|
||||
this.setMeasuredDimension(widthAndState, heightAndState);
|
||||
}
|
||||
|
||||
public layoutNativeView(left: number, top: number, right: number, bottom: number): void {
|
||||
//
|
||||
}
|
||||
|
@ -205,8 +205,11 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
}
|
||||
|
||||
private _measureHorizontal(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
||||
const widthMode = getMeasureSpecMode(widthMeasureSpec);
|
||||
const widthSize = getMeasureSpecSize(widthMeasureSpec);
|
||||
const widthMode = getMeasureSpecMode(widthMeasureSpec);
|
||||
const heightSize = getMeasureSpecSize(heightMeasureSpec);
|
||||
const heightMode = getMeasureSpecMode(heightMeasureSpec);
|
||||
|
||||
let childState = 0;
|
||||
|
||||
this._flexLines.length = 0;
|
||||
@ -231,7 +234,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
continue;
|
||||
}
|
||||
|
||||
child._updateEffectiveLayoutValues(this);
|
||||
child._updateEffectiveLayoutValues(widthSize, widthMode, heightSize, heightMode);
|
||||
let lp = child; // child.style;
|
||||
if (FlexboxLayout.getAlignSelf(child) === "stretch") {
|
||||
flexLine._indicesAlignSelfStretch.push(i);
|
||||
@ -321,8 +324,10 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
}
|
||||
|
||||
private _measureVertical(widthMeasureSpec, heightMeasureSpec): void {
|
||||
let heightMode = getMeasureSpecMode(heightMeasureSpec);
|
||||
let heightSize = getMeasureSpecSize(heightMeasureSpec);
|
||||
const widthSize = getMeasureSpecSize(widthMeasureSpec);
|
||||
const widthMode = getMeasureSpecMode(widthMeasureSpec);
|
||||
const heightSize = getMeasureSpecSize(heightMeasureSpec);
|
||||
const heightMode = getMeasureSpecMode(heightMeasureSpec);
|
||||
let childState = 0;
|
||||
|
||||
this._flexLines.length = 0;
|
||||
@ -346,7 +351,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
|
||||
continue;
|
||||
}
|
||||
|
||||
child._updateEffectiveLayoutValues(this);
|
||||
child._updateEffectiveLayoutValues(widthSize, widthMode, heightSize, heightMode);
|
||||
const lp = child; // .style;
|
||||
if (FlexboxLayout.getAlignSelf(child) === "stretch") {
|
||||
flexLine._indicesAlignSelfStretch.push(i);
|
||||
|
@ -3,17 +3,6 @@ import { LayoutBase } from "./layout-base";
|
||||
|
||||
export * from "./layout-base";
|
||||
export class Layout extends LayoutBase implements LayoutDefinition {
|
||||
nativeViewProtected: UIView;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.nativeViewProtected = UIView.new();
|
||||
}
|
||||
|
||||
get ios(): UIView {
|
||||
return this.nativeViewProtected;
|
||||
}
|
||||
|
||||
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
||||
// Don't call super because it will measure the native element.
|
||||
}
|
||||
|
@ -75,7 +75,6 @@ class UIViewControllerImpl extends UIViewController {
|
||||
|
||||
public viewWillAppear(animated: boolean): void {
|
||||
super.viewWillAppear(animated);
|
||||
|
||||
const owner = this._owner.get();
|
||||
if (!owner) {
|
||||
return;
|
||||
@ -254,6 +253,13 @@ class UIViewControllerImpl extends UIViewController {
|
||||
}
|
||||
}
|
||||
|
||||
public viewWillLayoutSubviews(): void {
|
||||
super.viewWillLayoutSubviews();
|
||||
|
||||
const owner = this._owner.get();
|
||||
iosView.updateConstraints(this, owner);
|
||||
}
|
||||
|
||||
public viewDidLayoutSubviews(): void {
|
||||
super.viewDidLayoutSubviews();
|
||||
|
||||
@ -264,8 +270,8 @@ class UIViewControllerImpl extends UIViewController {
|
||||
|
||||
const whiteColor = new Color("white").ios;
|
||||
export class Page extends PageBase {
|
||||
public viewController: UIViewControllerImpl;
|
||||
nativeViewProtected: UIView;
|
||||
viewController: UIViewControllerImpl;
|
||||
|
||||
private _ios: UIViewControllerImpl;
|
||||
public _enableLoadedEvents: boolean;
|
||||
@ -277,6 +283,8 @@ export class Page extends PageBase {
|
||||
constructor() {
|
||||
super();
|
||||
const controller = UIViewControllerImpl.initWithOwner(new WeakRef(this));
|
||||
const view = UIView.alloc().initWithFrame(getter(UIScreen, UIScreen.mainScreen).bounds);
|
||||
controller.view.addSubview(view);
|
||||
this.viewController = this._ios = controller;
|
||||
this.nativeViewProtected = controller.view;
|
||||
this.nativeViewProtected.backgroundColor = whiteColor;
|
||||
@ -298,12 +306,6 @@ export class Page extends PageBase {
|
||||
//
|
||||
}
|
||||
|
||||
public _onContentChanged(oldView: View, newView: View) {
|
||||
super._onContentChanged(oldView, newView);
|
||||
this._removeNativeView(oldView);
|
||||
this._addNativeView(newView);
|
||||
}
|
||||
|
||||
@profile
|
||||
public onLoaded() {
|
||||
// loaded/unloaded events are handled in page viewWillAppear/viewDidDisappear
|
||||
@ -321,40 +323,6 @@ export class Page extends PageBase {
|
||||
}
|
||||
}
|
||||
|
||||
private _addNativeView(view: View) {
|
||||
if (view) {
|
||||
if (traceEnabled()) {
|
||||
traceWrite("Native: Adding " + view + " to " + this, traceCategories.ViewHierarchy);
|
||||
}
|
||||
if (view.ios instanceof UIView) {
|
||||
this._ios.view.addSubview(view.ios);
|
||||
} else {
|
||||
const viewController = view.ios instanceof UIViewController ? view.ios : view.viewController;
|
||||
if (viewController) {
|
||||
this._ios.addChildViewController(view.ios);
|
||||
this._ios.view.addSubview(view.ios.view);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private _removeNativeView(view: View) {
|
||||
if (view) {
|
||||
if (traceEnabled()) {
|
||||
traceWrite("Native: Removing " + view + " from " + this, traceCategories.ViewHierarchy);
|
||||
}
|
||||
if (view.ios instanceof UIView) {
|
||||
view.ios.removeFromSuperview();
|
||||
} else {
|
||||
const viewController = view.ios instanceof UIViewController ? view.ios : view.viewController;
|
||||
if (viewController) {
|
||||
view.ios.removeFromParentViewController();
|
||||
view.ios.view.removeFromSuperview();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _showNativeModalView(parent: Page, context: any, closeCallback: Function, fullscreen?: boolean) {
|
||||
super._showNativeModalView(parent, context, closeCallback, fullscreen);
|
||||
this._modalParent = parent;
|
||||
@ -421,23 +389,6 @@ export class Page extends PageBase {
|
||||
}
|
||||
}
|
||||
|
||||
public _updateEffectiveLayoutValues(parent: View): void {
|
||||
super._updateEffectiveLayoutValues(parent);
|
||||
|
||||
// Patch vertical margins to respect status bar height
|
||||
if (!this.backgroundSpanUnderStatusBar) {
|
||||
const style = this.style;
|
||||
|
||||
const parentHeightMeasureSpec = parent._currentHeightMeasureSpec;
|
||||
const parentHeightMeasureSize = layout.getMeasureSpecSize(parentHeightMeasureSpec) - uiUtils.ios.getStatusBarHeight();
|
||||
const parentHeightMeasureMode = layout.getMeasureSpecMode(parentHeightMeasureSpec);
|
||||
const parentAvailableHeight = parentHeightMeasureMode === layout.UNSPECIFIED ? -1 : parentHeightMeasureSize;
|
||||
|
||||
this.effectiveMarginTop = PercentLength.toDevicePixels(style.marginTop, 0, parentAvailableHeight);
|
||||
this.effectiveMarginBottom = PercentLength.toDevicePixels(style.marginBottom, 0, parentAvailableHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number) {
|
||||
const width = layout.getMeasureSpecSize(widthMeasureSpec);
|
||||
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
|
||||
@ -450,9 +401,7 @@ export class Page extends PageBase {
|
||||
View.measureChild(this, this.actionBar, widthMeasureSpec, layout.makeMeasureSpec(height, layout.AT_MOST));
|
||||
}
|
||||
|
||||
const heightSpec = layout.makeMeasureSpec(height, heightMode);
|
||||
|
||||
const result = View.measureChild(this, this.layoutView, widthMeasureSpec, heightSpec);
|
||||
const result = View.measureChild(this, this.layoutView, widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
const measureWidth = Math.max(result.measuredWidth, this.effectiveMinWidth);
|
||||
const measureHeight = Math.max(result.measuredHeight, this.effectiveMinHeight);
|
||||
@ -468,30 +417,58 @@ export class Page extends PageBase {
|
||||
View.layoutChild(this, this.layoutView, 0, top, right - left, bottom);
|
||||
}
|
||||
|
||||
public _addViewToNativeVisualTree(view: View): boolean {
|
||||
public _addViewToNativeVisualTree(child: View, atIndex: number): boolean {
|
||||
// ActionBar is handled by the UINavigationController
|
||||
if (view === this.actionBar) {
|
||||
if (child === this.actionBar) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't add modal pages our visual tree.
|
||||
if (child !== this.content) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super._addViewToNativeVisualTree(view);
|
||||
const nativeParent = this.nativeViewProtected.subviews[0];
|
||||
const nativeChild = child.nativeViewProtected;
|
||||
|
||||
const viewController = child.ios instanceof UIViewController ? child.ios : child.viewController;
|
||||
if (viewController) {
|
||||
this.viewController.addChildViewController(viewController);
|
||||
}
|
||||
|
||||
if (nativeParent && nativeChild) {
|
||||
if (typeof atIndex !== "number" || atIndex >= nativeParent.subviews.count) {
|
||||
nativeParent.addSubview(nativeChild);
|
||||
} else {
|
||||
nativeParent.insertSubviewAtIndex(nativeChild, atIndex);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public _removeViewFromNativeVisualTree(view: View): void {
|
||||
public _removeViewFromNativeVisualTree(child: View): void {
|
||||
// ActionBar is handled by the UINavigationController
|
||||
if (view === this.actionBar) {
|
||||
if (child === this.actionBar) {
|
||||
return;
|
||||
}
|
||||
|
||||
super._removeViewFromNativeVisualTree(view);
|
||||
const viewController = child.ios instanceof UIViewController ? child.ios : child.viewController;
|
||||
if (viewController) {
|
||||
viewController.removeFromParentViewController();
|
||||
}
|
||||
|
||||
super._removeViewFromNativeVisualTree(child);
|
||||
}
|
||||
|
||||
[actionBarHiddenProperty.setNative](value: boolean) {
|
||||
this._updateEnableSwipeBackNavigation(value);
|
||||
if (this.isLoaded) {
|
||||
// Update nav-bar visibility with disabled animations
|
||||
this.updateActionBar(true);
|
||||
}
|
||||
invalidateTopmostController(this.viewController);
|
||||
|
||||
// Update nav-bar visibility with disabled animations
|
||||
this.updateActionBar(true);
|
||||
}
|
||||
|
||||
[statusBarStyleProperty.getDefault](): UIBarStyle {
|
||||
@ -509,3 +486,31 @@ export class Page extends PageBase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function invalidateTopmostController(controller: UIViewController): void {
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
controller.view.setNeedsLayout();
|
||||
|
||||
const presentedViewController = controller.presentedViewController;
|
||||
if (presentedViewController) {
|
||||
return invalidateTopmostController(presentedViewController);
|
||||
}
|
||||
|
||||
const childControllers = controller.childViewControllers;
|
||||
let size = controller.childViewControllers.count;
|
||||
while (size > 0) {
|
||||
const childController = childControllers[--size];
|
||||
if (childController instanceof UITabBarController) {
|
||||
invalidateTopmostController(childController.selectedViewController);
|
||||
} else if (childController instanceof UINavigationController) {
|
||||
invalidateTopmostController(childController.topViewController);
|
||||
} else if (childController instanceof UISplitViewController) {
|
||||
invalidateTopmostController(childController.viewControllers.lastObject);
|
||||
} else {
|
||||
invalidateTopmostController(childController);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
import { ScrollEventData } from ".";
|
||||
import { View, layout, ScrollViewBase, scrollBarIndicatorVisibleProperty } from "./scroll-view-common";
|
||||
// HACK: Webpack. Use a fully-qualified import to allow resolve.extensions(.ios.js) to
|
||||
// kick in. `../utils` doesn't seem to trigger the webpack extensions mechanism.
|
||||
import * as uiUtils from "tns-core-modules/ui/utils";
|
||||
|
||||
export * from "./scroll-view-common";
|
||||
|
||||
@ -143,10 +146,21 @@ export class ScrollView extends ScrollViewBase {
|
||||
const width = (right - left);
|
||||
const height = (bottom - top);
|
||||
|
||||
if (this.orientation === "horizontal") {
|
||||
View.layoutChild(this, this.layoutView, 0, 0, Math.max(this._contentMeasuredWidth, width), height);
|
||||
let verticalInset: number;
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const inset = nativeView.adjustedContentInset;
|
||||
// Prior iOS 11
|
||||
if (inset === undefined) {
|
||||
verticalInset = -layout.toDevicePixels(nativeView.contentOffset.y);
|
||||
verticalInset += getTabBarHeight(this);
|
||||
} else {
|
||||
View.layoutChild(this, this.layoutView, 0, 0, width, Math.max(this._contentMeasuredHeight, height));
|
||||
verticalInset = layout.toDevicePixels(inset.bottom + inset.top);
|
||||
}
|
||||
|
||||
if (this.orientation === "horizontal") {
|
||||
View.layoutChild(this, this.layoutView, 0, 0, Math.max(this._contentMeasuredWidth, width), height - verticalInset);
|
||||
} else {
|
||||
View.layoutChild(this, this.layoutView, 0, 0, width, Math.max(this._contentMeasuredHeight, height - verticalInset));
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,4 +169,18 @@ export class ScrollView extends ScrollViewBase {
|
||||
}
|
||||
}
|
||||
|
||||
function getTabBarHeight(scrollView: ScrollView): number {
|
||||
let parent = scrollView.parent;
|
||||
while (parent) {
|
||||
const controller = parent.viewController;
|
||||
if (controller instanceof UITabBarController) {
|
||||
return uiUtils.ios.getActualHeight(controller.tabBar);
|
||||
}
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScrollView.prototype.recycleNativeView = "auto";
|
@ -126,14 +126,24 @@ function updateItemIconPosition(tabBarItem: UITabBarItem): void {
|
||||
|
||||
export class TabViewItem extends TabViewItemBase {
|
||||
private __controller: UIViewController;
|
||||
public setViewController(controller: UIViewController) {
|
||||
private _setNeedsLayoutOnSuperview: boolean;
|
||||
public setViewController(controller: UIViewController, nativeView: UIView) {
|
||||
this.__controller = controller;
|
||||
this.setNativeView(controller.view);
|
||||
this.setNativeView(nativeView);
|
||||
this._setNeedsLayoutOnSuperview = controller.view !== nativeView;
|
||||
}
|
||||
|
||||
public requestLayout(): void {
|
||||
super.requestLayout();
|
||||
if (this._setNeedsLayoutOnSuperview) {
|
||||
this.nativeViewProtected.superview.setNeedsLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public disposeNativeView() {
|
||||
this.__controller = undefined;
|
||||
this.setNativeView(undefined);
|
||||
this._setNeedsLayoutOnSuperview = false;
|
||||
}
|
||||
|
||||
public _update() {
|
||||
@ -207,6 +217,19 @@ export class TabView extends TabViewBase {
|
||||
//
|
||||
}
|
||||
|
||||
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
||||
const width = layout.getMeasureSpecSize(widthMeasureSpec);
|
||||
const widthMode = layout.getMeasureSpecMode(widthMeasureSpec);
|
||||
|
||||
const height = layout.getMeasureSpecSize(heightMeasureSpec);
|
||||
const heightMode = layout.getMeasureSpecMode(heightMeasureSpec);
|
||||
|
||||
const widthAndState = View.resolveSizeAndState(width, width, widthMode, 0);
|
||||
const heightAndState = View.resolveSizeAndState(height, height, heightMode, 0);
|
||||
|
||||
this.setMeasuredDimension(widthAndState, heightAndState);
|
||||
}
|
||||
|
||||
public _onViewControllerShown(viewController: UIViewController) {
|
||||
// This method could be called with the moreNavigationController or its list controller, so we have to check.
|
||||
if (traceEnabled()) {
|
||||
@ -262,17 +285,21 @@ export class TabView extends TabViewBase {
|
||||
let newController: UIViewController = item.view ? item.view.viewController : null;
|
||||
|
||||
if (newController) {
|
||||
item.setViewController(newController, newController.view);
|
||||
return newController;
|
||||
}
|
||||
|
||||
if (item.view.ios instanceof UIViewController) {
|
||||
newController = item.view.ios;
|
||||
item.setViewController(newController, newController.view);
|
||||
} else if (item.view.ios && item.view.ios.controller instanceof UIViewController) {
|
||||
newController = item.view.ios.controller;
|
||||
item.setViewController(newController, newController.view);
|
||||
} else {
|
||||
newController = iosView.UILayoutViewController.initWithOwner(new WeakRef(item.view));
|
||||
newController.view = item.view.nativeViewProtected;
|
||||
newController.view.addSubview(item.view.nativeViewProtected);
|
||||
item.view.viewController = newController;
|
||||
item.setViewController(newController, item.view.nativeViewProtected);
|
||||
}
|
||||
|
||||
return newController;
|
||||
@ -291,8 +318,6 @@ export class TabView extends TabViewBase {
|
||||
for (let i = 0; i < length; i++) {
|
||||
const item = items[i];
|
||||
const controller = this.getViewController(item);
|
||||
item.setViewController(controller);
|
||||
|
||||
const icon = this._getIcon(item.iconSource);
|
||||
const tabBarItem = UITabBarItem.alloc().initWithTitleImageTag((item.title || ""), icon, i);
|
||||
if (!icon) {
|
||||
|
@ -3,8 +3,6 @@
|
||||
declare function float(num: number): any;
|
||||
declare function long(num: number): any;
|
||||
|
||||
declare var app;
|
||||
declare var telerik;
|
||||
declare var gc: () => void;
|
||||
|
||||
declare function float(num: number): any;
|
||||
@ -12,45 +10,4 @@ declare function long(num: number): any;
|
||||
|
||||
interface ArrayConstructor {
|
||||
create(type: any, count: number): any;
|
||||
}
|
||||
|
||||
declare module android {
|
||||
module support {
|
||||
module v4 {
|
||||
module widget {
|
||||
class DrawerLayout {
|
||||
constructor(context: android.content.Context);
|
||||
}
|
||||
|
||||
module DrawerLayout {
|
||||
class DrawerListener implements IDrawerListener {
|
||||
constructor(implementation: IDrawerListener);
|
||||
|
||||
onDrawerClosed(drawerView: android.view.View): void;
|
||||
onDrawerOpened(drawerView: android.view.View): void;
|
||||
onDrawerSlide(drawerView: android.view.View, offset: number): void;
|
||||
onDrawerStateChanged(newState: number): void;
|
||||
}
|
||||
|
||||
class LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
|
||||
constructor(width: number, height: number, gravity?: number);
|
||||
gravity: number;
|
||||
}
|
||||
|
||||
interface IDrawerListener {
|
||||
onDrawerClosed(drawerView: android.view.View): void;
|
||||
onDrawerOpened(drawerView: android.view.View): void;
|
||||
onDrawerSlide(drawerView: android.view.View, offset: number): void;
|
||||
onDrawerStateChanged(newState: number): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module app {
|
||||
class ActionBarDrawerToggle {
|
||||
constructor(activity: android.app.Activity, layout: widget.DrawerLayout, imageResId: number, openResId: number, closeResId: number);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user