iOS Frame, Page and TabView measure/layout methods removed. We now rely on the framework positioning. This will result in a change that width, height, minWidth, minHeight, margins not respected on these controls

iOS layout positioning now respects native properties like automaticallyAdjustsScrollViewInsets, edgesForExtendedLayout, extendedLayoutIncludesOpaqueBars, navigationBar.translucent, tabBar.translucent
Removed frame-tests.ios.ts - those tests are now invalid
Added new layout tests inside page-tests.ios.ts
Commented few asserts in scroll-view-tests
View now expose ios namespace with layoutView method and UILayoutViewController used by page, tab-view and application module
ViewBase now expose viewController property that should be set from all widgets that are using viewcontrollers internally (like Page, Frame, TabView)
ViewBase now sets ios property to either the view returned from createNativeView or to nativeViewProptected
fragment.transitions now use animation/transition start to add fragments to waitingQueue. Before we did it manually in navigate/goBack. This way we can reuse the fragment.transition when calling showDialog. Also when animation/transition ends we check the animation/transition to see if this fragment should be set as current.
Frame expose new loadViewFromEntry method (to load a view from URI)
Frame navigation happens once frame is loaded
Frame now supports Page as a child in XML
Fixed GridLayout row, rowSpan, column, columnSpan properties type
Fixed bug in GridLayout where add/remove of columns/rows won't update the internal state of the grid (backport from android when GridLayout is recycled)
ListView will no longer invalidate layout when cell is removed
Fixed bug in ScrollView ios where effectiveMinWidth/Height was multiplied to density (it is already on device pixels so no need to multiply)
TabView android now calls loaded only on the selected child (not all)
Core refactoring
This commit is contained in:
Hristo Hristov
2017-09-27 10:32:28 +03:00
parent 7bc0daf222
commit af034089ca
38 changed files with 934 additions and 923 deletions

View File

@@ -124,6 +124,8 @@ setApplication(androidApp);
let mainEntry: NavigationEntry;
let started = false;
// NOTE: for backwards compatibility. Remove for 4.0.0.
let createRootFrame = true;
export function start(entry?: NavigationEntry | string) {
if (started) {
throw new Error("Application is already started.");
@@ -137,6 +139,15 @@ export function start(entry?: NavigationEntry | string) {
}
}
export function shouldCreateRootFrame(): boolean {
return createRootFrame;
}
export function run(entry?: NavigationEntry | string) {
createRootFrame = false;
start(entry);
}
export function getMainEntry() {
return mainEntry;
}

View File

@@ -167,10 +167,25 @@ export function on(event: "livesync", callback: (args: EventData) => void);
export function off(eventNames: string, callback?: any, thisArg?: any);
/**
* Deprecated. Use application run.
* Call this method to start the application. Important: All code after this method call will not be executed!
*/
export function start(entry?: NavigationEntry | string);
/**
* Call this method to run the application. Important: All code after this method call will not be executed!
* Compared to start this method won't create Frame as root view.
*/
export function run(entry?: NavigationEntry | string);
//@private
/**
* Internal method use to check if a root Frame should be automatically created as root view.
* @private
*/
export function shouldCreateRootFrame(): boolean;
//@endprivate
/**
* A basic method signature to hook an event listener (shortcut alias to the addEventListener method).
* @param eventNames - String corresponding to events (e.g. "onLaunch"). Optionally could be used more events separated by `,` (e.g. "onLaunch", "onSuspend").

View File

@@ -14,7 +14,8 @@ import {
// First reexport so that app module is initialized.
export * from "./application-common";
import { Frame, View, NavigationEntry } from "../ui/frame";
import { ios as iosView } from "../ui/core/view";
import { Frame, View, NavigationEntry, loadViewFromEntry } from "../ui/frame";
import { ios } from "../ui/utils";
import * as utils from "../utils/utils";
import { profile } from "../profiling";
@@ -25,27 +26,6 @@ class Responder extends UIResponder {
let displayedOnce = false;
class Window extends UIWindow {
public content;
initWithFrame(frame: CGRect): this {
const window = <this>super.initWithFrame(frame);
if (window) {
window.autoresizingMask = UIViewAutoresizing.None;
}
return window;
}
@profile
public layoutSubviews(): void {
if (utils.ios.MajorVersion < 9) {
ios._layoutRootView(this.content, utils.ios.getter(UIScreen, UIScreen.mainScreen).bounds);
} else {
ios._layoutRootView(this.content, this.frame);
}
}
}
class NotificationObserver extends NSObject {
private _onReceiveCallback: (notification: NSNotification) => void;
@@ -65,11 +45,9 @@ class NotificationObserver extends NSObject {
}
class IOSApplication implements IOSApplicationDefinition {
public rootController: any;
private _delegate: typeof UIApplicationDelegate;
private _currentOrientation = utils.ios.getter(UIDevice, UIDevice.currentDevice).orientation;
private _window: Window;
private _window: UIWindow;
private _observers: Array<NotificationObserver>;
constructor() {
@@ -82,11 +60,15 @@ class IOSApplication implements IOSApplicationDefinition {
this.addNotificationObserver(UIDeviceOrientationDidChangeNotification, this.orientationDidChange.bind(this));
}
get rootController(): UIViewController {
return this._window.rootViewController;
}
get nativeApp(): UIApplication {
return utils.ios.getter(UIApplication, UIApplication.sharedApplication);
}
get window(): Window {
get window(): UIWindow {
return this._window;
}
@@ -116,7 +98,8 @@ class IOSApplication implements IOSApplicationDefinition {
@profile
private didFinishLaunchingWithOptions(notification: NSNotification) {
this._window = <Window>Window.alloc().initWithFrame(utils.ios.getter(UIScreen, UIScreen.mainScreen).bounds);
this._window = UIWindow.alloc().initWithFrame(utils.ios.getter(UIScreen, UIScreen.mainScreen).bounds);
// TODO: Expose Window module so that it can we styled from XML & CSS
this._window.backgroundColor = utils.ios.getter(UIColor, UIColor.whiteColor);
const args: LaunchEventData = {
@@ -128,31 +111,16 @@ class IOSApplication implements IOSApplicationDefinition {
notify(args);
notify(<LoadAppCSSEventData>{ eventName: "loadAppCss", object: <any>this, cssFile: getCssFileName() });
let rootView = createRootView(args.root);
this._window.content = rootView;
if (rootView instanceof Frame) {
this.rootController = this._window.rootViewController = rootView.ios.controller;
}
else if (rootView.ios instanceof UIViewController) {
this.rootController = this._window.rootViewController = rootView.ios;
}
else if (rootView.ios instanceof UIView) {
let newController = UIViewController.new();
newController.view.addSubview(rootView.ios);
this.rootController = newController;
}
else {
throw new Error("Root should be either UIViewController or UIView");
}
const rootView = createRootView(args.root);
const controller = getViewController(rootView);
this._window.rootViewController = controller;
this._window.makeKeyAndVisible();
}
@profile
private didBecomeActive(notification: NSNotification) {
let ios = utils.ios.getter(UIApplication, UIApplication.sharedApplication);
let object = this;
const ios = utils.ios.getter(UIApplication, UIApplication.sharedApplication);
const object = this;
notify(<ApplicationEventData>{ eventName: resumeEvent, object, ios });
if (!displayedOnce) {
notify(<ApplicationEventData>{ eventName: displayedEvent, object, ios });
@@ -210,20 +178,20 @@ setApplication(iosApp);
let mainEntry: NavigationEntry;
function createRootView(v?: View) {
let rootView = v;
let frame: Frame;
let main: string | NavigationEntry;
if (!rootView) {
// try to navigate to the mainEntry (if specified)
main = mainEntry;
if (main) {
frame = new Frame();
frame.navigate(main);
if (mainEntry) {
if (createRootFrame) {
const frame = new Frame();
rootView = frame;
frame.navigate(mainEntry);
} else {
rootView = loadViewFromEntry(mainEntry);
}
} else {
// TODO: Throw an exception?
throw new Error("A Frame must be used to navigate to a Page.");
}
rootView = frame;
}
rootView._setupAsRootView({});
@@ -234,6 +202,8 @@ export function getMainEntry() {
return mainEntry;
}
// NOTE: for backwards compatibility. Remove for 4.0.0.
let createRootFrame = true;
let started: boolean = false;
export function start(entry?: string | NavigationEntry) {
mainEntry = typeof entry === "string" ? { moduleName: entry } : entry;
@@ -243,29 +213,47 @@ export function start(entry?: string | NavigationEntry) {
// Normal NativeScript app will need UIApplicationMain.
UIApplicationMain(0, null, null, iosApp && iosApp.delegate ? NSStringFromClass(<any>iosApp.delegate) : NSStringFromClass(Responder));
} else {
let rootView = createRootView();
const rootView = createRootView();
if (rootView) {
// Attach to the existing iOS app
var window = iosApp.nativeApp.keyWindow || (iosApp.nativeApp.windows.count > 0 && iosApp.nativeApp.windows[0]);
const window = iosApp.nativeApp.keyWindow || (iosApp.nativeApp.windows.count > 0 && iosApp.nativeApp.windows[0]);
if (window) {
var rootController = window.rootViewController;
const rootController = window.rootViewController;
if (rootController) {
rootController.presentViewControllerAnimatedCompletion(rootView.ios.controller, true, null);
ios._layoutRootView(rootView, utils.ios.getter(UIScreen, UIScreen.mainScreen).bounds);
const controller = getViewController(rootView);
rootController.presentViewControllerAnimatedCompletion(controller, true, null);
}
}
}
}
}
export function run(entry?: string | NavigationEntry) {
createRootFrame = false;
start(entry);
}
export function getNativeApplication(): UIApplication {
return iosApp.nativeApp;
}
function getViewController(view: View): UIViewController {
let viewController = 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;
return viewController;
} else {
throw new Error("Root should be either UIViewController or UIView");
}
}
global.__onLiveSync = function () {
if (!started) {
return;
}
livesync();
}
}