mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-26 11:17:04 +08:00
Implement Page background option to span under status bar (iOS only for the moment)
This commit is contained in:
@ -154,11 +154,16 @@ export class ActionBar extends common.ActionBar {
|
|||||||
let frame = <frameModule.Frame>this.page.frame;
|
let frame = <frameModule.Frame>this.page.frame;
|
||||||
if (frame) {
|
if (frame) {
|
||||||
let navBar: UIView = frame.ios.controller.navigationBar;
|
let navBar: UIView = frame.ios.controller.navigationBar;
|
||||||
let navBarSize = navBar.sizeThatFits(CGSizeMake(width, height));
|
if (!navBar.hidden) {
|
||||||
|
let navBarSize = navBar.sizeThatFits(CGSizeMake(
|
||||||
|
(widthMode === utils.layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : width,
|
||||||
|
(heightMode === utils.layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : height));
|
||||||
navBarWidth = navBarSize.width;
|
navBarWidth = navBarSize.width;
|
||||||
this._navigationBarHeight = navBarHeight = navBarSize.height;
|
navBarHeight = navBarSize.height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._navigationBarHeight = navBarHeight;
|
||||||
if (this.titleView) {
|
if (this.titleView) {
|
||||||
view.View.measureChild(this, this.titleView,
|
view.View.measureChild(this, this.titleView,
|
||||||
utils.layout.makeMeasureSpec(width, utils.layout.AT_MOST),
|
utils.layout.makeMeasureSpec(width, utils.layout.AT_MOST),
|
||||||
|
@ -244,7 +244,7 @@ export class View extends viewCommon.View {
|
|||||||
// When in landscape in iOS 7 there is transformation on the first subview of the window so we set frame to its subview.
|
// When in landscape in iOS 7 there is transformation on the first subview of the window so we set frame to its subview.
|
||||||
// in iOS 8 we set frame to subview again otherwise we get clipped.
|
// in iOS 8 we set frame to subview again otherwise we get clipped.
|
||||||
var nativeView: UIView;
|
var nativeView: UIView;
|
||||||
if (!this.parent && this._nativeView.subviews.count > 0 && !(<any>this)._isModal) {
|
if (!this.parent && this._nativeView.subviews.count > 0 && utils.ios.MajorVersion < 8) {
|
||||||
trace.write(this + " has no parent. Setting frame to first child instead.", trace.categories.Layout);
|
trace.write(this + " has no parent. Setting frame to first child instead.", trace.categories.Layout);
|
||||||
nativeView = (<UIView>this._nativeView.subviews[0]);
|
nativeView = (<UIView>this._nativeView.subviews[0]);
|
||||||
}
|
}
|
||||||
@ -287,9 +287,7 @@ export class CustomLayoutView extends View {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._view = new UIView();
|
this._view = new UIView();
|
||||||
this._view.autoresizesSubviews = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get ios(): UIView {
|
get ios(): UIView {
|
||||||
|
@ -6,6 +6,7 @@ import enums = require("ui/enums");
|
|||||||
import utils = require("utils/utils");
|
import utils = require("utils/utils");
|
||||||
import view = require("ui/core/view");
|
import view = require("ui/core/view");
|
||||||
import types = require("utils/types");
|
import types = require("utils/types");
|
||||||
|
import uiUtils = require("ui/utils");
|
||||||
|
|
||||||
global.moduleMerge(frameCommon, exports);
|
global.moduleMerge(frameCommon, exports);
|
||||||
|
|
||||||
@ -182,27 +183,47 @@ export class Frame extends frameCommon.Frame {
|
|||||||
|
|
||||||
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
|
||||||
|
|
||||||
var width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
|
let width = utils.layout.getMeasureSpecSize(widthMeasureSpec);
|
||||||
var widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
|
let widthMode = utils.layout.getMeasureSpecMode(widthMeasureSpec);
|
||||||
|
|
||||||
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
|
let height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
|
||||||
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
|
let heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
|
||||||
|
|
||||||
this._widthMeasureSpec = widthMeasureSpec;
|
this._widthMeasureSpec = widthMeasureSpec;
|
||||||
this._heightMeasureSpec = heightMeasureSpec;
|
this._heightMeasureSpec = heightMeasureSpec;
|
||||||
|
|
||||||
var result = view.View.measureChild(this, this.currentPage, widthMeasureSpec, heightMeasureSpec);
|
let result = this.measurePage(this.currentPage);
|
||||||
|
let widthAndState = view.View.resolveSizeAndState(result.measuredWidth, width, widthMode, 0);
|
||||||
var widthAndState = view.View.resolveSizeAndState(result.measuredWidth, width, widthMode, 0);
|
let heightAndState = view.View.resolveSizeAndState(result.measuredHeight, height, heightMode, 0);
|
||||||
var heightAndState = view.View.resolveSizeAndState(result.measuredHeight, height, heightMode, 0);
|
|
||||||
|
|
||||||
this.setMeasuredDimension(widthAndState, heightAndState);
|
this.setMeasuredDimension(widthAndState, heightAndState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public measurePage(page: pages.Page): { measuredWidth: number; measuredHeight: number } {
|
||||||
|
|
||||||
|
// If background does not span under statusbar - reduce available height.
|
||||||
|
let heightSpec: number = this._heightMeasureSpec;
|
||||||
|
if (page && !page.backgroundSpanUnderStatusBar) {
|
||||||
|
let height = utils.layout.getMeasureSpecSize(this._heightMeasureSpec);
|
||||||
|
let heightMode = utils.layout.getMeasureSpecMode(this._heightMeasureSpec);
|
||||||
|
let statusBarHeight = uiUtils.ios.getStatusBarHeight();
|
||||||
|
heightSpec = utils.layout.makeMeasureSpec(height - statusBarHeight, heightMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view.View.measureChild(this, page, this._widthMeasureSpec, heightSpec);
|
||||||
|
}
|
||||||
|
|
||||||
public onLayout(left: number, top: number, right: number, bottom: number): void {
|
public onLayout(left: number, top: number, right: number, bottom: number): void {
|
||||||
this._layoutWidth = right - left;
|
this._layoutWidth = right - left;
|
||||||
this._layoutheight = bottom - top;
|
this._layoutheight = bottom - top;
|
||||||
view.View.layoutChild(this, this.currentPage, 0, 0, right - left, bottom - top);
|
this.layoutPage(this.currentPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public layoutPage(page: pages.Page): void {
|
||||||
|
// If background does not span under statusbar - reduce available height and adjust top offset.
|
||||||
|
let statusBarHeight = (page && !page.backgroundSpanUnderStatusBar) ? uiUtils.ios.getStatusBarHeight() : 0;
|
||||||
|
|
||||||
|
view.View.layoutChild(this, page, 0, statusBarHeight, this._layoutWidth, this._layoutheight);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get navigationBarHeight(): number {
|
public get navigationBarHeight(): number {
|
||||||
@ -227,8 +248,6 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
|
|||||||
}
|
}
|
||||||
|
|
||||||
public viewDidLoad(): void {
|
public viewDidLoad(): void {
|
||||||
this.view.autoresizesSubviews = false;
|
|
||||||
this.view.autoresizingMask = UIViewAutoresizing.UIViewAutoresizingNone;
|
|
||||||
this._owner.onLoaded();
|
this._owner.onLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,8 +271,8 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
|
|||||||
}
|
}
|
||||||
|
|
||||||
frame._addView(newPage);
|
frame._addView(newPage);
|
||||||
view.View.measureChild(frame, newPage, frame._widthMeasureSpec, frame._heightMeasureSpec);
|
frame.measurePage(newPage);
|
||||||
view.View.layoutChild(frame, newPage, 0, 0, frame._layoutWidth, frame._layoutheight);
|
frame.layoutPage(newPage)
|
||||||
}
|
}
|
||||||
else if (newPage.parent !== frame) {
|
else if (newPage.parent !== frame) {
|
||||||
throw new Error("Page is already shown on another frame.");
|
throw new Error("Page is already shown on another frame.");
|
||||||
|
@ -7,9 +7,7 @@ export class Layout extends layoutBase.LayoutBase implements definition.Layout {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._view = new UIView();
|
this._view = new UIView();
|
||||||
this._view.autoresizesSubviews = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get ios(): UIView {
|
get ios(): UIView {
|
||||||
|
@ -142,7 +142,6 @@ export class ListView extends common.ListView {
|
|||||||
|
|
||||||
this._ios = new UITableView();
|
this._ios = new UITableView();
|
||||||
this._ios.registerClassForCellReuseIdentifier(ListViewCell.class(), CELLIDENTIFIER);
|
this._ios.registerClassForCellReuseIdentifier(ListViewCell.class(), CELLIDENTIFIER);
|
||||||
this._ios.autoresizesSubviews = false;
|
|
||||||
this._ios.autoresizingMask = UIViewAutoresizing.UIViewAutoresizingNone;
|
this._ios.autoresizingMask = UIViewAutoresizing.UIViewAutoresizingNone;
|
||||||
this._ios.estimatedRowHeight = DEFAULT_HEIGHT;
|
this._ios.estimatedRowHeight = DEFAULT_HEIGHT;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import contentView = require("ui/content-view");
|
import {ContentView} from "ui/content-view";
|
||||||
import view = require("ui/core/view");
|
import view = require("ui/core/view");
|
||||||
import dts = require("ui/page");
|
import dts = require("ui/page");
|
||||||
import frame = require("ui/frame");
|
import frame = require("ui/frame");
|
||||||
@ -6,17 +6,19 @@ import styleModule = require("../styling/style");
|
|||||||
import styleScope = require("../styling/style-scope");
|
import styleScope = require("../styling/style-scope");
|
||||||
import fs = require("file-system");
|
import fs = require("file-system");
|
||||||
import frameCommon = require("../frame/frame-common");
|
import frameCommon = require("../frame/frame-common");
|
||||||
import actionBar = require("ui/action-bar");
|
import {ActionBar} from "ui/action-bar";
|
||||||
import dependencyObservable = require("ui/core/dependency-observable");
|
import {DependencyObservable, PropertyMetadata, PropertyMetadataSettings, PropertyChangeData, Property, ValueSource} from "ui/core/dependency-observable";
|
||||||
|
|
||||||
import proxy = require("ui/core/proxy");
|
import proxy = require("ui/core/proxy");
|
||||||
|
|
||||||
var actionBarHiddenProperty = new dependencyObservable.Property(
|
// on Android we explicitly set propertySettings to None because android will invalidate its layout (skip unnecessary native call).
|
||||||
"actionBarHidden",
|
var AffectsLayout = global.android ? PropertyMetadataSettings.None : PropertyMetadataSettings.AffectsLayout;
|
||||||
"Page",
|
|
||||||
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.AffectsLayout)
|
|
||||||
);
|
|
||||||
|
|
||||||
function onActionBarHiddenPropertyChanged(data: dependencyObservable.PropertyChangeData) {
|
var backgroundSpanUnderStatusBarProperty = new Property("backgroundSpanUnderStatusBar", "Page", new proxy.PropertyMetadata(false, AffectsLayout));
|
||||||
|
|
||||||
|
var actionBarHiddenProperty = new Property("actionBarHidden", "Page", new proxy.PropertyMetadata(undefined, AffectsLayout));
|
||||||
|
|
||||||
|
function onActionBarHiddenPropertyChanged(data: PropertyChangeData) {
|
||||||
var page = <Page>data.object;
|
var page = <Page>data.object;
|
||||||
if (page.isLoaded) {
|
if (page.isLoaded) {
|
||||||
page._updateActionBar(data.newValue);
|
page._updateActionBar(data.newValue);
|
||||||
@ -25,7 +27,8 @@ function onActionBarHiddenPropertyChanged(data: dependencyObservable.PropertyCha
|
|||||||
|
|
||||||
(<proxy.PropertyMetadata>actionBarHiddenProperty.metadata).onSetNativeValue = onActionBarHiddenPropertyChanged;
|
(<proxy.PropertyMetadata>actionBarHiddenProperty.metadata).onSetNativeValue = onActionBarHiddenPropertyChanged;
|
||||||
|
|
||||||
export class Page extends contentView.ContentView implements dts.Page {
|
export class Page extends ContentView implements dts.Page {
|
||||||
|
public static backgroundSpanUnderStatusBarProperty = backgroundSpanUnderStatusBarProperty;
|
||||||
public static actionBarHiddenProperty = actionBarHiddenProperty;
|
public static actionBarHiddenProperty = actionBarHiddenProperty;
|
||||||
public static navigatingToEvent = "navigatingTo";
|
public static navigatingToEvent = "navigatingTo";
|
||||||
public static navigatedToEvent = "navigatedTo";
|
public static navigatedToEvent = "navigatedTo";
|
||||||
@ -39,16 +42,16 @@ export class Page extends contentView.ContentView implements dts.Page {
|
|||||||
|
|
||||||
private _cssApplied: boolean;
|
private _cssApplied: boolean;
|
||||||
private _styleScope: styleScope.StyleScope = new styleScope.StyleScope();
|
private _styleScope: styleScope.StyleScope = new styleScope.StyleScope();
|
||||||
private _actionBar: actionBar.ActionBar;
|
private _actionBar: ActionBar;
|
||||||
|
|
||||||
constructor(options?: dts.Options) {
|
constructor(options?: dts.Options) {
|
||||||
super(options);
|
super(options);
|
||||||
this.actionBar = new actionBar.ActionBar();
|
this.actionBar = new ActionBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
public onLoaded() {
|
public onLoaded() {
|
||||||
// The default style of the page should be white background
|
// The default style of the page should be white background
|
||||||
this.style._setValue(styleModule.backgroundColorProperty, "white", dependencyObservable.ValueSource.Inherited);
|
this.style._setValue(styleModule.backgroundColorProperty, "white", ValueSource.Inherited);
|
||||||
|
|
||||||
this._applyCss();
|
this._applyCss();
|
||||||
|
|
||||||
@ -59,6 +62,14 @@ export class Page extends contentView.ContentView implements dts.Page {
|
|||||||
super.onLoaded();
|
super.onLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get backgroundSpanUnderStatusBar(): boolean {
|
||||||
|
return this._getValue(Page.backgroundSpanUnderStatusBarProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
set backgroundSpanUnderStatusBar(value: boolean) {
|
||||||
|
this._setValue(Page.backgroundSpanUnderStatusBarProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
get actionBarHidden(): boolean {
|
get actionBarHidden(): boolean {
|
||||||
return this._getValue(Page.actionBarHiddenProperty);
|
return this._getValue(Page.actionBarHiddenProperty);
|
||||||
}
|
}
|
||||||
@ -86,10 +97,10 @@ export class Page extends contentView.ContentView implements dts.Page {
|
|||||||
this._refreshCss();
|
this._refreshCss();
|
||||||
}
|
}
|
||||||
|
|
||||||
get actionBar(): actionBar.ActionBar {
|
get actionBar(): ActionBar {
|
||||||
return this._actionBar;
|
return this._actionBar;
|
||||||
}
|
}
|
||||||
set actionBar(value: actionBar.ActionBar) {
|
set actionBar(value: ActionBar) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
throw new Error("ActionBar cannot be null or undefined.");
|
throw new Error("ActionBar cannot be null or undefined.");
|
||||||
}
|
}
|
||||||
@ -198,7 +209,7 @@ export class Page extends contentView.ContentView implements dts.Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public _addChildFromBuilder(name: string, value: any) {
|
public _addChildFromBuilder(name: string, value: any) {
|
||||||
if (value instanceof actionBar.ActionBar) {
|
if (value instanceof ActionBar) {
|
||||||
this.actionBar = value;
|
this.actionBar = value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
10
ui/page/page.d.ts
vendored
10
ui/page/page.d.ts
vendored
@ -46,6 +46,11 @@ declare module "ui/page" {
|
|||||||
* Represents a logical unit for navigation (inside Frame).
|
* Represents a logical unit for navigation (inside Frame).
|
||||||
*/
|
*/
|
||||||
export class Page extends contentView.ContentView {
|
export class Page extends contentView.ContentView {
|
||||||
|
/**
|
||||||
|
* Dependency property that specify if page background should span under status bar.
|
||||||
|
*/
|
||||||
|
public static backgroundSpanUnderStatusBarProperty: dependencyObservable.Property;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dependency property used to hide the Navigation Bar in iOS and the Action Bar in Android.
|
* Dependency property used to hide the Navigation Bar in iOS and the Action Bar in Android.
|
||||||
*/
|
*/
|
||||||
@ -78,6 +83,11 @@ declare module "ui/page" {
|
|||||||
|
|
||||||
constructor(options?: Options)
|
constructor(options?: Options)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets or sets whether page background spans under status bar.
|
||||||
|
*/
|
||||||
|
backgroundSpanUnderStatusBar: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to hide the Navigation Bar in iOS and the Action Bar in Android.
|
* Used to hide the Navigation Bar in iOS and the Action Bar in Android.
|
||||||
*/
|
*/
|
||||||
|
@ -4,6 +4,8 @@ import {View} from "ui/core/view";
|
|||||||
import trace = require("trace");
|
import trace = require("trace");
|
||||||
import uiUtils = require("ui/utils");
|
import uiUtils = require("ui/utils");
|
||||||
import utils = require("utils/utils");
|
import utils = require("utils/utils");
|
||||||
|
import {device} from "platform";
|
||||||
|
import {DeviceType} from "ui/enums";
|
||||||
|
|
||||||
global.moduleMerge(pageCommon, exports);
|
global.moduleMerge(pageCommon, exports);
|
||||||
|
|
||||||
@ -22,23 +24,67 @@ class UIViewControllerImpl extends UIViewController {
|
|||||||
|
|
||||||
public didRotateFromInterfaceOrientation(fromInterfaceOrientation: number) {
|
public didRotateFromInterfaceOrientation(fromInterfaceOrientation: number) {
|
||||||
trace.write(this._owner + " didRotateFromInterfaceOrientation(" + fromInterfaceOrientation + ")", trace.categories.ViewHierarchy);
|
trace.write(this._owner + " didRotateFromInterfaceOrientation(" + fromInterfaceOrientation + ")", trace.categories.ViewHierarchy);
|
||||||
if (this._owner._isModal) {
|
|
||||||
var parentBounds = (<any>this._owner)._UIModalPresentationFormSheet ? (<UIView>this._owner._nativeView).superview.bounds : UIScreen.mainScreen().bounds;
|
|
||||||
uiUtils.ios._layoutRootView(this._owner, parentBounds);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public viewDidLoad() {
|
public viewDidLoad() {
|
||||||
trace.write(this._owner + " viewDidLoad", trace.categories.ViewHierarchy);
|
trace.write(this._owner + " viewDidLoad", trace.categories.ViewHierarchy);
|
||||||
this.view.autoresizesSubviews = false;
|
|
||||||
this.view.autoresizingMask = UIViewAutoresizing.UIViewAutoresizingNone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public viewDidLayoutSubviews() {
|
public viewDidLayoutSubviews() {
|
||||||
trace.write(this._owner + " viewDidLayoutSubviews, isLoaded = " + this._owner.isLoaded, trace.categories.ViewHierarchy);
|
trace.write(this._owner + " viewDidLayoutSubviews, isLoaded = " + this._owner.isLoaded, trace.categories.ViewHierarchy);
|
||||||
|
if (!this._owner.isLoaded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._owner._isModal) {
|
if (this._owner._isModal) {
|
||||||
var parentBounds = (<any>this._owner)._UIModalPresentationFormSheet ? this._owner._nativeView.superview.bounds : UIScreen.mainScreen().bounds;
|
let isTablet = device.deviceType === DeviceType.Tablet;
|
||||||
uiUtils.ios._layoutRootView(this._owner, parentBounds);
|
let isFullScreen = !this._owner._UIModalPresentationFormSheet || !isTablet;
|
||||||
|
let frame = isFullScreen ? UIScreen.mainScreen().bounds : this.view.frame;
|
||||||
|
let origin = frame.origin;
|
||||||
|
let size = frame.size;
|
||||||
|
let width = size.width;
|
||||||
|
let height = size.height;
|
||||||
|
let mode: number = utils.layout.EXACTLY;
|
||||||
|
|
||||||
|
let superViewRotationRadians;
|
||||||
|
if (this.view.superview) {
|
||||||
|
let transform = this.view.superview.transform;
|
||||||
|
superViewRotationRadians = atan2f(transform.b, transform.a);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils.ios.MajorVersion < 8 && utils.ios.isLandscape() && !superViewRotationRadians) {
|
||||||
|
// in iOS 7 when in landscape we switch width with height because on device they don't change even when rotated.
|
||||||
|
width = size.height;
|
||||||
|
height = size.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bottom = height;
|
||||||
|
let statusBarHeight = uiUtils.ios.getStatusBarHeight();
|
||||||
|
let statusBarVisible = !UIApplication.sharedApplication().statusBarHidden;
|
||||||
|
let backgroundSpanUnderStatusBar = this._owner.backgroundSpanUnderStatusBar;
|
||||||
|
if (statusBarVisible && !backgroundSpanUnderStatusBar) {
|
||||||
|
height -= statusBarHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
let widthSpec = utils.layout.makeMeasureSpec(width, mode);
|
||||||
|
let heightSpec = utils.layout.makeMeasureSpec(height, mode);
|
||||||
|
|
||||||
|
View.measureChild(null, this._owner, widthSpec, heightSpec);
|
||||||
|
let top = ((backgroundSpanUnderStatusBar && isFullScreen) || utils.ios.MajorVersion < 8 || !isFullScreen) ? 0 : statusBarHeight;
|
||||||
|
View.layoutChild(null, this._owner, 0, top, width, bottom);
|
||||||
|
|
||||||
|
if (utils.ios.MajorVersion < 8) {
|
||||||
|
if (!backgroundSpanUnderStatusBar && (!isTablet || isFullScreen)) {
|
||||||
|
if (utils.ios.isLandscape() && !superViewRotationRadians) {
|
||||||
|
this.view.center = CGPointMake(this.view.center.x - statusBarHeight, this.view.center.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.view.center = CGPointMake(this.view.center.x, this.view.center.y + statusBarHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trace.write(this._owner + ", native frame = " + NSStringFromCGRect(this.view.frame), trace.categories.Layout);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this._owner._updateLayout();
|
this._owner._updateLayout();
|
||||||
@ -64,6 +110,7 @@ export class Page extends pageCommon.Page {
|
|||||||
private _ios: UIViewController;
|
private _ios: UIViewController;
|
||||||
public _enableLoadedEvents: boolean;
|
public _enableLoadedEvents: boolean;
|
||||||
public _isModal: boolean = false;
|
public _isModal: boolean = false;
|
||||||
|
public _UIModalPresentationFormSheet: boolean = false;
|
||||||
|
|
||||||
constructor(options?: definition.Options) {
|
constructor(options?: definition.Options) {
|
||||||
super(options);
|
super(options);
|
||||||
@ -139,18 +186,18 @@ export class Page extends pageCommon.Page {
|
|||||||
|
|
||||||
if (fullscreen) {
|
if (fullscreen) {
|
||||||
this._ios.modalPresentationStyle = UIModalPresentationStyle.UIModalPresentationFullScreen;
|
this._ios.modalPresentationStyle = UIModalPresentationStyle.UIModalPresentationFullScreen;
|
||||||
uiUtils.ios._layoutRootView(this, UIScreen.mainScreen().bounds);
|
//uiUtils.ios._layoutRootView(this, UIScreen.mainScreen().bounds);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this._ios.modalPresentationStyle = UIModalPresentationStyle.UIModalPresentationFormSheet;
|
this._ios.modalPresentationStyle = UIModalPresentationStyle.UIModalPresentationFormSheet;
|
||||||
(<any>this)._UIModalPresentationFormSheet = true;
|
this._UIModalPresentationFormSheet = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var that = this;
|
var that = this;
|
||||||
parent.ios.presentViewControllerAnimatedCompletion(this._ios, false, function completion() {
|
parent.ios.presentViewControllerAnimatedCompletion(this._ios, false, function completion() {
|
||||||
if (!fullscreen) {
|
if (!fullscreen) {
|
||||||
// We can measure and layout the modal page after we know its parent's dimensions.
|
// We can measure and layout the modal page after we know its parent's dimensions.
|
||||||
uiUtils.ios._layoutRootView(that, that._nativeView.superview.bounds);
|
//uiUtils.ios._layoutRootView(that, that._nativeView.superview.bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
that._raiseShownModallyEvent(parent, context, closeCallback);
|
that._raiseShownModallyEvent(parent, context, closeCallback);
|
||||||
@ -158,9 +205,10 @@ export class Page extends pageCommon.Page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected _hideNativeModalView(parent: Page) {
|
protected _hideNativeModalView(parent: Page) {
|
||||||
parent._ios.dismissModalViewControllerAnimated(false);
|
|
||||||
this._isModal = false;
|
this._isModal = false;
|
||||||
(<any>this)._UIModalPresentationFormSheet = false;
|
this._UIModalPresentationFormSheet = false;
|
||||||
|
parent.requestLayout();
|
||||||
|
parent._ios.dismissModalViewControllerAnimated(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public _updateActionBar(hidden: boolean) {
|
public _updateActionBar(hidden: boolean) {
|
||||||
@ -180,6 +228,15 @@ export class Page extends pageCommon.Page {
|
|||||||
|
|
||||||
let actionBarWidth: number = 0;
|
let actionBarWidth: number = 0;
|
||||||
let actionBarHeight: number = 0;
|
let actionBarHeight: number = 0;
|
||||||
|
|
||||||
|
// If background span under statusbar reduce available height for page content.
|
||||||
|
let statusBarHeight = this.backgroundSpanUnderStatusBar ? uiUtils.ios.getStatusBarHeight() : 0;
|
||||||
|
|
||||||
|
// Phones does not support fullScreen=false for modal pages so we reduce statusbar only when on tablet and not in fullscreen
|
||||||
|
if (this._isModal && this._UIModalPresentationFormSheet && device.deviceType === DeviceType.Tablet) {
|
||||||
|
statusBarHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.frame && this.frame._getNavBarVisible(this)) {
|
if (this.frame && this.frame._getNavBarVisible(this)) {
|
||||||
// Measure ActionBar with the full height.
|
// Measure ActionBar with the full height.
|
||||||
let actionBarSize = View.measureChild(this, this.actionBar, widthMeasureSpec, heightMeasureSpec);
|
let actionBarSize = View.measureChild(this, this.actionBar, widthMeasureSpec, heightMeasureSpec);
|
||||||
@ -187,7 +244,7 @@ export class Page extends pageCommon.Page {
|
|||||||
actionBarHeight = actionBarSize.measuredHeight;
|
actionBarHeight = actionBarSize.measuredHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
let heightSpec = utils.layout.makeMeasureSpec(height - actionBarHeight, heightMode);
|
let heightSpec = utils.layout.makeMeasureSpec(height - actionBarHeight - statusBarHeight, heightMode);
|
||||||
|
|
||||||
// Measure content with height - navigationBarHeight. Here we could use actionBarSize.measuredHeight probably.
|
// Measure content with height - navigationBarHeight. Here we could use actionBarSize.measuredHeight probably.
|
||||||
let result = View.measureChild(this, this.content, widthMeasureSpec, heightSpec);
|
let result = View.measureChild(this, this.content, widthMeasureSpec, heightSpec);
|
||||||
@ -204,8 +261,18 @@ export class Page extends pageCommon.Page {
|
|||||||
public onLayout(left: number, top: number, right: number, bottom: number) {
|
public onLayout(left: number, top: number, right: number, bottom: number) {
|
||||||
View.layoutChild(this, this.actionBar, 0, 0, right - left, bottom - top);
|
View.layoutChild(this, this.actionBar, 0, 0, right - left, bottom - top);
|
||||||
|
|
||||||
let navigationBarHeight = this.frame ? this.frame.navigationBarHeight : 0;
|
let navigationBarHeight: number = 0;
|
||||||
View.layoutChild(this, this.content, 0, navigationBarHeight, right - left, bottom - top);
|
if (this.frame && this.frame._getNavBarVisible(this)) {
|
||||||
|
navigationBarHeight = this.actionBar.getMeasuredHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusBarHeight = this.backgroundSpanUnderStatusBar ? uiUtils.ios.getStatusBarHeight() : 0;
|
||||||
|
// Phones does not support fullScreen=false for modal pages so we reduce statusbar only when on tablet and not in fullscreen
|
||||||
|
if (this._isModal && this._UIModalPresentationFormSheet && device.deviceType === DeviceType.Tablet) {
|
||||||
|
statusBarHeight = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
View.layoutChild(this, this.content, 0, navigationBarHeight + statusBarHeight, right - left, bottom - top);
|
||||||
}
|
}
|
||||||
|
|
||||||
public _addViewToNativeVisualTree(view: View): boolean {
|
public _addViewToNativeVisualTree(view: View): boolean {
|
||||||
|
@ -254,8 +254,9 @@ export class TabView extends common.TabView {
|
|||||||
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
|
var height = utils.layout.getMeasureSpecSize(heightMeasureSpec);
|
||||||
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
|
var heightMode = utils.layout.getMeasureSpecMode(heightMeasureSpec);
|
||||||
|
|
||||||
this._tabBarHeight = uiUtils.ios.getActualHeight(this._ios.tabBar);
|
this._tabBarHeight = TabView.measureHelper(this._ios.tabBar, width, widthMode, height, heightMode).height;
|
||||||
this._navBarHeight = uiUtils.ios.getActualHeight(this._ios.moreNavigationController.navigationBar);
|
let moreNavBarVisible = !!this._ios.moreNavigationController.navigationBar.window;
|
||||||
|
this._navBarHeight = moreNavBarVisible ? TabView.measureHelper(this._ios.moreNavigationController.navigationBar, width, widthMode, height, heightMode).height : 0;
|
||||||
|
|
||||||
var density = utils.layout.getDisplayDensity();
|
var density = utils.layout.getDisplayDensity();
|
||||||
var measureWidth = 0;
|
var measureWidth = 0;
|
||||||
@ -263,7 +264,7 @@ export class TabView extends common.TabView {
|
|||||||
|
|
||||||
var child = this._selectedView;
|
var child = this._selectedView;
|
||||||
if (child) {
|
if (child) {
|
||||||
var childHeightMeasureSpec = utils.layout.makeMeasureSpec(height - (this._navBarHeight + this._tabBarHeight), heightMode);
|
var childHeightMeasureSpec = utils.layout.makeMeasureSpec(height - this._navBarHeight - this._tabBarHeight, heightMode);
|
||||||
var childSize = view.View.measureChild(this, child, widthMeasureSpec, childHeightMeasureSpec);
|
var childSize = view.View.measureChild(this, child, widthMeasureSpec, childHeightMeasureSpec);
|
||||||
|
|
||||||
measureHeight = childSize.measuredHeight;
|
measureHeight = childSize.measuredHeight;
|
||||||
@ -289,4 +290,9 @@ export class TabView extends common.TabView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static measureHelper(nativeView: UIView, width: number, widthMode: number, height: number, heightMode: number): CGSize {
|
||||||
|
return nativeView.sizeThatFits(CGSizeMake(
|
||||||
|
(widthMode === utils.layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : width,
|
||||||
|
(heightMode === utils.layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : height));
|
||||||
|
}
|
||||||
}
|
}
|
2
ui/utils.d.ts
vendored
2
ui/utils.d.ts
vendored
@ -8,5 +8,7 @@
|
|||||||
export function getActualHeight(uiView: UIView): number;
|
export function getActualHeight(uiView: UIView): number;
|
||||||
|
|
||||||
export function _layoutRootView(rootView: view.View, parentBounds: CGRect): void;
|
export function _layoutRootView(rootView: view.View, parentBounds: CGRect): void;
|
||||||
|
|
||||||
|
export function getStatusBarHeight(): number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,76 +1,52 @@
|
|||||||
import view = require("ui/core/view");
|
import {View} from "ui/core/view";
|
||||||
import utils = require("utils/utils");
|
import utils = require("utils/utils");
|
||||||
|
|
||||||
export module ios {
|
export module ios {
|
||||||
export function getActualHeight(uiView: UIView): number {
|
export function getActualHeight(view: UIView): number {
|
||||||
if (uiView.window && !uiView.hidden) {
|
if (view.window && !view.hidden) {
|
||||||
return uiView.frame.size.height;
|
return view.frame.size.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function _layoutRootView(rootView: view.View, parentBounds: CGRect) {
|
export function getStatusBarHeight(): number {
|
||||||
|
var app = UIApplication.sharedApplication();
|
||||||
|
if (!app || app.statusBarHidden) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusFrame = app.statusBarFrame;
|
||||||
|
return Math.min(statusFrame.size.width, statusFrame.size.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function _layoutRootView(rootView: View, parentBounds: CGRect) {
|
||||||
if (!rootView || !parentBounds) {
|
if (!rootView || !parentBounds) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var landscape = utils.ios.isLandscape();
|
let size = parentBounds.size;
|
||||||
var iOSMajorVersion = utils.ios.MajorVersion;
|
let width = size.width;
|
||||||
var size = parentBounds.size;
|
let height = size.height;
|
||||||
var width = size.width;
|
|
||||||
var height = size.height;
|
|
||||||
|
|
||||||
//trace.write("--------------------------------------------", "LayoutRootView.iOS");
|
|
||||||
//trace.write("| Layout Root View", "LayoutRootView.iOS");
|
|
||||||
//trace.write("| rootView: " + rootView, "LayoutRootView.iOS");
|
|
||||||
//trace.write("| parentBounds: " + NSStringFromCGRect(parentBounds), "LayoutRootView.iOS");
|
|
||||||
//trace.write("| UIScreen.mainScreen().bounds: " + NSStringFromCGRect(UIScreen.mainScreen().bounds), "LayoutRootView.iOS");
|
|
||||||
//trace.write("| _isModal: " + (<any>rootView)._isModal, "LayoutRootView.iOS");
|
|
||||||
//trace.write("| _UIModalPresentationFormSheet: " + (<any>rootView)._UIModalPresentationFormSheet, "LayoutRootView.iOS");
|
|
||||||
//trace.write("| landscape: " + landscape, "LayoutRootView.iOS");
|
|
||||||
//trace.write("| iOSMajorVersion: " + iOSMajorVersion, "LayoutRootView.iOS");
|
|
||||||
var superview = (<UIView>rootView._nativeView).superview;
|
var superview = (<UIView>rootView._nativeView).superview;
|
||||||
//trace.write("| superview: " + superview, "LayoutRootView.iOS");
|
|
||||||
var superViewRotationRadians;
|
var superViewRotationRadians;
|
||||||
if (superview) {
|
if (superview) {
|
||||||
superViewRotationRadians = atan2f(superview.transform.b, superview.transform.a);
|
superViewRotationRadians = atan2f(superview.transform.b, superview.transform.a);
|
||||||
//trace.write("| superViewRotationRadians: " + superViewRotationRadians + " rad.", "LayoutRootView.iOS");
|
|
||||||
//trace.write("| superview.bounds: " + NSStringFromCGRect(superview.bounds), "LayoutRootView.iOS");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iOSMajorVersion < 8 && landscape && !superViewRotationRadians) {
|
if (utils.ios.MajorVersion < 8 && utils.ios.isLandscape() && !superViewRotationRadians) {
|
||||||
// in iOS 7 when in landscape we switch width with height because on device they don't change even when rotated.
|
// in iOS 7 when in landscape we switch width with height because on device they don't change even when rotated.
|
||||||
//trace.write("| >>> Detected iOS 7 device in landscape mode and superview is not rotated. Manually swapping width and height...", "LayoutRootView.iOS");
|
|
||||||
width = size.height;
|
width = size.height;
|
||||||
height = size.width;
|
height = size.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
var statusBarHeight;
|
|
||||||
if (UIApplication.sharedApplication().statusBarHidden || ((<any>rootView)._UIModalPresentationFormSheet && !CGSizeEqualToSize(parentBounds.size, UIScreen.mainScreen().bounds.size))) {
|
|
||||||
statusBarHeight = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Status bar section
|
|
||||||
var statusFrame = UIApplication.sharedApplication().statusBarFrame;
|
|
||||||
try {
|
|
||||||
statusBarHeight = Math.min(statusFrame.size.width, statusFrame.size.height);
|
|
||||||
} catch (ex) {
|
|
||||||
console.log("exception: " + ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//trace.write("| UIApplication.sharedApplication().statusBarHidden: " + UIApplication.sharedApplication().statusBarHidden, "LayoutRootView.iOS");
|
|
||||||
//trace.write("| statusBarHeight: " + statusBarHeight, "LayoutRootView.iOS");
|
|
||||||
|
|
||||||
var origin = parentBounds.origin;
|
var origin = parentBounds.origin;
|
||||||
var left = origin.x;
|
var left = origin.x;
|
||||||
var top = origin.y + statusBarHeight;
|
var top = origin.y;
|
||||||
|
|
||||||
var widthSpec = utils.layout.makeMeasureSpec(width, utils.layout.EXACTLY);
|
var widthSpec = utils.layout.makeMeasureSpec(width, utils.layout.EXACTLY);
|
||||||
var heightSpec = utils.layout.makeMeasureSpec(height - statusBarHeight, utils.layout.EXACTLY);
|
var heightSpec = utils.layout.makeMeasureSpec(height, utils.layout.EXACTLY);
|
||||||
|
|
||||||
//trace.write("| >>> Will measure and layout with {{" + left + ", " + top + "}{" + width + ", " + height + "}}", "LayoutRootView.iOS");
|
|
||||||
//trace.write("--------------------------------------------", "LayoutRootView.iOS");
|
|
||||||
|
|
||||||
rootView.measure(widthSpec, heightSpec);
|
rootView.measure(widthSpec, heightSpec);
|
||||||
rootView.layout(left, top, width, height);
|
rootView.layout(left, top, width, height);
|
||||||
|
Reference in New Issue
Block a user