From 597b38216ca20fdef48d1b30bfe0a7c63cfcded8 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 20 Mar 2017 15:09:46 +0200 Subject: [PATCH 1/2] Layout round instead of cailing Add helper method to layout module to convert to/from dips to px and measure the native view whiteSpace affects layout added for iOS Fix bug in switch onMeasure implementation Fix bug in cssValueToDevicePixels iOS implementation ActionBar for iOS is measured with AT_MOST modifier --- .../ui/action-bar/action-bar.ios.ts | 22 +- tns-core-modules/ui/core/view/view-common.ts | 16 +- tns-core-modules/ui/core/view/view.android.ts | 17 +- tns-core-modules/ui/core/view/view.ios.ts | 41 ++-- .../ui/html-view/html-view.ios.ts | 31 +-- tns-core-modules/ui/label/label.ios.ts | 14 +- tns-core-modules/ui/page/page.ios.ts | 2 +- tns-core-modules/ui/styling/background.ios.ts | 22 +- .../ui/styling/style-properties.ts | 8 +- tns-core-modules/ui/styling/style/style.d.ts | 20 +- tns-core-modules/ui/styling/style/style.ts | 211 +----------------- tns-core-modules/ui/switch/switch.ios.ts | 7 +- tns-core-modules/ui/tab-view/tab-view.ios.ts | 15 +- .../ui/text-base/text-base-common.ts | 1 + tns-core-modules/utils/utils-common.ts | 14 +- tns-core-modules/utils/utils.android.ts | 9 + tns-core-modules/utils/utils.d.ts | 30 ++- tns-core-modules/utils/utils.ios.ts | 12 + 18 files changed, 162 insertions(+), 330 deletions(-) diff --git a/tns-core-modules/ui/action-bar/action-bar.ios.ts b/tns-core-modules/ui/action-bar/action-bar.ios.ts index fd94143f95..f5d74ebabd 100644 --- a/tns-core-modules/ui/action-bar/action-bar.ios.ts +++ b/tns-core-modules/ui/action-bar/action-bar.ios.ts @@ -232,24 +232,22 @@ export class ActionBar extends ActionBarBase { private _navigationBarHeight: number = 0; public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number) { - let width = layout.getMeasureSpecSize(widthMeasureSpec); - let widthMode = layout.getMeasureSpecMode(widthMeasureSpec); + const width = layout.getMeasureSpecSize(widthMeasureSpec); + const widthMode = layout.getMeasureSpecMode(widthMeasureSpec); - let height = layout.getMeasureSpecSize(heightMeasureSpec); - let heightMode = layout.getMeasureSpecMode(heightMeasureSpec); + const height = layout.getMeasureSpecSize(heightMeasureSpec); + const heightMode = layout.getMeasureSpecMode(heightMeasureSpec); let navBarWidth = 0; let navBarHeight = 0; - - let frame = this.page.frame; + + const frame = this.page.frame; if (frame) { let navBar: UIView = frame.ios.controller.navigationBar; if (!navBar.hidden) { - let navBarSize = navBar.sizeThatFits(CGSizeMake( - (widthMode === layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : width, - (heightMode === layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : height)); - navBarWidth = layout.toDevicePixels(navBarSize.width); - navBarHeight = layout.toDevicePixels(navBarSize.height); + const desiredSize = layout.measureNativeView(navBar, width, widthMode, height, heightMode); + navBarWidth = desiredSize.width; + navBarHeight = desiredSize.height; } } @@ -276,7 +274,7 @@ export class ActionBar extends ActionBarBase { View.layoutChild(this, this.titleView, 0, 0, right - left, this._navigationBarHeight); this.actionItems.getItems().forEach((actionItem) => { if (actionItem.actionView && actionItem.actionView.ios) { - let measuredWidth = actionItem.actionView.getMeasuredWidth();  + let measuredWidth = actionItem.actionView.getMeasuredWidth(); let measuredHeight = actionItem.actionView.getMeasuredHeight(); View.layoutChild(this, actionItem.actionView, 0, 0, measuredWidth, measuredHeight); } diff --git a/tns-core-modules/ui/core/view/view-common.ts b/tns-core-modules/ui/core/view/view-common.ts index 4c1d2927e4..b199a10e73 100644 --- a/tns-core-modules/ui/core/view/view-common.ts +++ b/tns-core-modules/ui/core/view/view-common.ts @@ -572,20 +572,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { let measureHeight = 0; if (child && !child.isCollapsed) { - let width = layout.getMeasureSpecSize(widthMeasureSpec); - let widthMode = layout.getMeasureSpecMode(widthMeasureSpec); - - let height = layout.getMeasureSpecSize(heightMeasureSpec); - let heightMode = layout.getMeasureSpecMode(heightMeasureSpec); - child._updateEffectiveLayoutValues(parent); let style = child.style; let horizontalMargins = child.effectiveMarginLeft + child.effectiveMarginRight; let verticalMargins = child.effectiveMarginTop + child.effectiveMarginBottom; - let childWidthMeasureSpec = ViewCommon.getMeasureSpec(width, widthMode, horizontalMargins, child.effectiveWidth, style.horizontalAlignment === "stretch"); - let childHeightMeasureSpec = ViewCommon.getMeasureSpec(height, heightMode, verticalMargins, child.effectiveHeight, style.verticalAlignment === "stretch"); + let childWidthMeasureSpec = ViewCommon.getMeasureSpec(widthMeasureSpec, horizontalMargins, child.effectiveWidth, style.horizontalAlignment === "stretch"); + let 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); @@ -599,7 +593,10 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { return { measuredWidth: measureWidth, measuredHeight: measureHeight }; } - private static getMeasureSpec(parentLength: number, parentSpecMode: number, margins: number, childLength: number, stretched: boolean): number { + private static getMeasureSpec(parentSpec: number, margins: number, childLength: number, stretched: boolean): number { + const parentLength = layout.getMeasureSpecSize(parentSpec); + const parentSpecMode = layout.getMeasureSpecMode(parentSpec); + let resultSize: number; let resultMode: number; @@ -607,6 +604,7 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { if (childLength >= 0) { // If mode !== UNSPECIFIED we take the smaller of parentLength and childLength // Otherwise we will need to clip the view but this is not possible in all Android API levels. + // TODO: remove Math.min(parentLength, childLength) resultSize = parentSpecMode === layout.UNSPECIFIED ? childLength : Math.min(parentLength, childLength); resultMode = layout.EXACTLY; } diff --git a/tns-core-modules/ui/core/view/view.android.ts b/tns-core-modules/ui/core/view/view.android.ts index 449f866b9a..f3e10fb52e 100644 --- a/tns-core-modules/ui/core/view/view.android.ts +++ b/tns-core-modules/ui/core/view/view.android.ts @@ -370,9 +370,9 @@ export class View extends ViewCommon { get [horizontalAlignmentProperty.native](): HorizontalAlignment { return org.nativescript.widgets.ViewHelper.getHorizontalAlignment(this.nativeView); } - set [horizontalAlignmentProperty.native](value: HorizontalAlignment)  { - const  nativeView = this.nativeView; - const  lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams(); + set [horizontalAlignmentProperty.native](value: HorizontalAlignment) { + const nativeView = this.nativeView; + const lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams(); // Set only if params gravity exists. if (lp.gravity !== undefined) { switch (value) { @@ -397,8 +397,8 @@ export class View extends ViewCommon { return org.nativescript.widgets.ViewHelper.getVerticalAlignment(this.nativeView); } set [verticalAlignmentProperty.native](value: VerticalAlignment) { - const  nativeView = this.nativeView; - const  lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams(); + const nativeView = this.nativeView; + const lp: any = nativeView.getLayoutParams() || new org.nativescript.widgets.CommonLayoutParams(); // Set only if params gravity exists. if (lp.gravity !== undefined) { switch (value) { @@ -562,6 +562,7 @@ interface NativePercentLengthPropertyOptions { setPixels: NativeSetter; setPercent?: NativeSetter } + function createNativePercentLengthProperty(options: NativePercentLengthPropertyOptions) { const { key, auto = 0 } = options; let setPixels, getPixels, setPercent; @@ -590,11 +591,11 @@ function createNativePercentLengthProperty(options: NativePercentLengthPropertyO if (length == "auto") { // tslint:disable-line setPixels(this.nativeView, auto); } else if (typeof length === "number") { - setPixels(this.nativeView, Math.ceil(length * layout.getDisplayDensity())); + setPixels(this.nativeView, layout.round(layout.toDevicePixels(length))); } else if (length.unit == "dip") { // tslint:disable-line - setPixels(this.nativeView, Math.ceil(length.value * layout.getDisplayDensity())); + setPixels(this.nativeView, layout.round(layout.toDevicePixels(length.value))); } else if (length.unit == "px") { // tslint:disable-line - setPixels(this.nativeView, Math.ceil(length.value)); + setPixels(this.nativeView, layout.round(length.value)); } else if (length.unit == "%") { // tslint:disable-line setPercent(this.nativeView, length.value); } else { diff --git a/tns-core-modules/ui/core/view/view.ios.ts b/tns-core-modules/ui/core/view/view.ios.ts index 47840d388c..ae3a4aff12 100644 --- a/tns-core-modules/ui/core/view/view.ios.ts +++ b/tns-core-modules/ui/core/view/view.ios.ts @@ -3,8 +3,8 @@ import { Point, View as ViewDefinition } from "."; import { ios, Background } from "../../styling/background"; import { - ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty, - traceEnabled, traceWrite, traceCategories + ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty, + traceEnabled, traceWrite, traceCategories } from "./view-common"; import { @@ -100,35 +100,26 @@ export class View extends ViewCommon { } public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void { - let view = this.nativeView; - let nativeWidth = 0; - let nativeHeight = 0; - - let width = layout.getMeasureSpecSize(widthMeasureSpec); - let widthMode = layout.getMeasureSpecMode(widthMeasureSpec); + const view = this.nativeView; + const width = layout.getMeasureSpecSize(widthMeasureSpec); + const widthMode = layout.getMeasureSpecMode(widthMeasureSpec); - let height = layout.getMeasureSpecSize(heightMeasureSpec); - let heightMode = layout.getMeasureSpecMode(heightMeasureSpec); + const height = layout.getMeasureSpecSize(heightMeasureSpec); + const heightMode = layout.getMeasureSpecMode(heightMeasureSpec); + let nativeWidth = 0; + let nativeHeight = 0; if (view) { - if (widthMode === layout.UNSPECIFIED) { - width = Number.POSITIVE_INFINITY; - } - - if (heightMode === layout.UNSPECIFIED) { - height = Number.POSITIVE_INFINITY; - } - - let nativeSize = view.sizeThatFits(CGSizeMake(layout.toDeviceIndependentPixels(width), layout.toDeviceIndependentPixels(height))); - nativeWidth = layout.toDevicePixels(nativeSize.width); - nativeHeight = layout.toDevicePixels(nativeSize.height); + const nativeSize = layout.measureNativeView(view, width, widthMode, height, heightMode); + nativeWidth = nativeSize.width; + nativeHeight = nativeSize.height; } - let measureWidth = Math.max(nativeWidth, this.effectiveMinWidth); - let measureHeight = Math.max(nativeHeight, this.effectiveMinHeight); + const measureWidth = Math.max(nativeWidth, this.effectiveMinWidth); + const measureHeight = Math.max(nativeHeight, this.effectiveMinHeight); - let widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0); - let heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0); + const widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0); + const heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0); this.setMeasuredDimension(widthAndState, heightAndState); } diff --git a/tns-core-modules/ui/html-view/html-view.ios.ts b/tns-core-modules/ui/html-view/html-view.ios.ts index 1f59458bf2..efc4ee0605 100644 --- a/tns-core-modules/ui/html-view/html-view.ios.ts +++ b/tns-core-modules/ui/html-view/html-view.ios.ts @@ -1,5 +1,5 @@ import { - HtmlViewBase, View, layout, htmlProperty + HtmlViewBase, View, layout, htmlProperty } from "./html-view-common"; export * from "./html-view-common"; @@ -30,29 +30,20 @@ export class HtmlView extends HtmlViewBase { var nativeView = this._nativeView; if (nativeView) { - let width = layout.getMeasureSpecSize(widthMeasureSpec); - let widthMode = layout.getMeasureSpecMode(widthMeasureSpec); + const width = layout.getMeasureSpecSize(widthMeasureSpec); + const widthMode = layout.getMeasureSpecMode(widthMeasureSpec); - let height = layout.getMeasureSpecSize(heightMeasureSpec); - let heightMode = layout.getMeasureSpecMode(heightMeasureSpec); + const height = layout.getMeasureSpecSize(heightMeasureSpec); + const heightMode = layout.getMeasureSpecMode(heightMeasureSpec); - if (widthMode === layout.UNSPECIFIED) { - width = Number.POSITIVE_INFINITY; - } + const desiredSize = layout.measureNativeView(nativeView, width, widthMode, height, heightMode); - if (heightMode === layout.UNSPECIFIED) { - height = Number.POSITIVE_INFINITY; - } + const labelWidth = Math.min(desiredSize.width, width); + const measureWidth = Math.max(labelWidth, this.effectiveMinWidth); + const measureHeight = Math.max(desiredSize.height, this.effectiveMinHeight); - let nativeSize = nativeView.sizeThatFits(CGSizeMake(width, height)); - let labelWidth = layout.toDevicePixels(nativeSize.width); - - labelWidth = Math.min(labelWidth, width); - let measureWidth = Math.max(labelWidth, this.effectiveMinWidth); - let measureHeight = Math.max(layout.toDevicePixels(nativeSize.height), this.effectiveMinHeight); - - let widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0); - let heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0); + const widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0); + const heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0); this.setMeasuredDimension(widthAndState, heightAndState); } diff --git a/tns-core-modules/ui/label/label.ios.ts b/tns-core-modules/ui/label/label.ios.ts index b864c5a981..c7dd33b610 100644 --- a/tns-core-modules/ui/label/label.ios.ts +++ b/tns-core-modules/ui/label/label.ios.ts @@ -73,26 +73,18 @@ export class Label extends TextBase implements LabelDefinition { let height = layout.getMeasureSpecSize(heightMeasureSpec); let heightMode = layout.getMeasureSpecMode(heightMeasureSpec); - if (widthMode === layout.UNSPECIFIED) { - width = Number.POSITIVE_INFINITY; - } - - if (heightMode === layout.UNSPECIFIED) { - height = Number.POSITIVE_INFINITY; - } - this._fixedSize = (widthMode === layout.EXACTLY ? FixedSize.WIDTH : FixedSize.NONE) | (heightMode === layout.EXACTLY ? FixedSize.HEIGHT : FixedSize.NONE); - let nativeSize = nativeView.sizeThatFits(CGSizeMake(layout.toDeviceIndependentPixels(width), layout.toDeviceIndependentPixels(height))); - let labelWidth = layout.toDevicePixels(nativeSize.width); + const nativeSize = layout.measureNativeView(nativeView, width, widthMode, height, heightMode); + let labelWidth = nativeSize.width; if (this.textWrap) { labelWidth = Math.min(labelWidth, width); } let measureWidth = Math.max(labelWidth, this.effectiveMinWidth); - let measureHeight = Math.max(layout.toDevicePixels(nativeSize.height), this.effectiveMinHeight); + let measureHeight = Math.max(nativeSize.height, this.effectiveMinHeight); let widthAndState = View.resolveSizeAndState(measureWidth, width, widthMode, 0); let heightAndState = View.resolveSizeAndState(measureHeight, height, heightMode, 0); diff --git a/tns-core-modules/ui/page/page.ios.ts b/tns-core-modules/ui/page/page.ios.ts index 1cae90ea33..1face8b131 100644 --- a/tns-core-modules/ui/page/page.ios.ts +++ b/tns-core-modules/ui/page/page.ios.ts @@ -514,7 +514,7 @@ export class Page extends PageBase { if (!this._modalParent && this.frame && this.frame._getNavBarVisible(this)) { // Measure ActionBar with the full height. - let actionBarSize = View.measureChild(this, this.actionBar, widthMeasureSpec, heightMeasureSpec); + let actionBarSize = View.measureChild(this, this.actionBar, widthMeasureSpec, layout.makeMeasureSpec(height, layout.AT_MOST)); actionBarWidth = actionBarSize.measuredWidth; actionBarHeight = actionBarSize.measuredHeight; } diff --git a/tns-core-modules/ui/styling/background.ios.ts b/tns-core-modules/ui/styling/background.ios.ts index d32de6cb0e..ec4e1640fe 100644 --- a/tns-core-modules/ui/styling/background.ios.ts +++ b/tns-core-modules/ui/styling/background.ios.ts @@ -145,19 +145,15 @@ function _flipImage(originalImage: UIImage): UIImage { return flippedImage; } -function cssValueToDevicePixels(source: string, total: number): number { - let result; +function cssValueToDevicePixels(source: string, totalPx: number): number { source = source.trim(); - if (source.indexOf("px") !== -1) { - result = parseFloat(source.replace("px", "")); - } - else if (source.indexOf("%") !== -1 && total > 0) { - result = (parseFloat(source.replace("%", "")) / 100) * layout.toDeviceIndependentPixels(total); + return parseFloat(source.replace("px", "")); + } else if (source.indexOf("%") !== -1 && totalPx > 0) { + return (parseFloat(source.replace("%", "")) / 100) * totalPx; } else { - result = parseFloat(source); + return layout.toDevicePixels(parseFloat(source)); } - return layout.toDevicePixels(result); } function drawNonUniformBorders(nativeView: NativeView, background: Background) { @@ -293,10 +289,10 @@ function drawClipPath(nativeView: UIView, background: Background) { const layerSize = layerBounds.size; const bounds = { - left: layerOrigin.x, - top: layerOrigin.y, - bottom: layerSize.height, - right: layerSize.width + left: layout.toDevicePixels(layerOrigin.x), + top: layout.toDevicePixels(layerOrigin.y), + bottom: layout.toDevicePixels(layerSize.height), + right: layout.toDevicePixels(layerSize.width) }; if (bounds.right === 0 || bounds.bottom === 0) { diff --git a/tns-core-modules/ui/styling/style-properties.ts b/tns-core-modules/ui/styling/style-properties.ts index 8e9e8614c4..b2d16d2184 100644 --- a/tns-core-modules/ui/styling/style-properties.ts +++ b/tns-core-modules/ui/styling/style-properties.ts @@ -59,16 +59,16 @@ function toDevicePixelsCommon(length: PercentLength, auto: number, parentAvailab return auto; } if (typeof length === "number") { - return Math.ceil(layout.getDisplayDensity() * length); + return layout.round(layout.toDevicePixels(length)); } switch (length.unit) { case "px": - return Math.ceil(length.value); + return layout.round(length.value); case "%": - return Math.round(parentAvailableWidth * length.value); + return layout.round(parentAvailableWidth * length.value); case "dip": default: - return Math.ceil(layout.getDisplayDensity() * length.value); + return layout.round(layout.toDevicePixels(length.value)); } } diff --git a/tns-core-modules/ui/styling/style/style.d.ts b/tns-core-modules/ui/styling/style/style.d.ts index baf2cc0615..87f0219f97 100644 --- a/tns-core-modules/ui/styling/style/style.d.ts +++ b/tns-core-modules/ui/styling/style/style.d.ts @@ -134,14 +134,14 @@ export class Style extends Observable { public view: ViewBase; //flexbox layout properties - flexDirection: FlexDirection; - flexWrap: FlexWrap; - justifyContent: JustifyContent; - alignItems: AlignItems; - alignContent: AlignContent; - order: Order; - flexGrow: FlexGrow; - flexShrink: FlexShrink; - flexWrapBefore: FlexWrapBefore; - alignSelf: AlignSelf; + public flexDirection: FlexDirection; + public flexWrap: FlexWrap; + public justifyContent: JustifyContent; + public alignItems: AlignItems; + public alignContent: AlignContent; + public order: Order; + public flexGrow: FlexGrow; + public flexShrink: FlexShrink; + public flexWrapBefore: FlexWrapBefore; + public alignSelf: AlignSelf; } diff --git a/tns-core-modules/ui/styling/style/style.ts b/tns-core-modules/ui/styling/style/style.ts index b03d20ad2f..999dc5247d 100644 --- a/tns-core-modules/ui/styling/style/style.ts +++ b/tns-core-modules/ui/styling/style/style.ts @@ -17,9 +17,6 @@ export class Style extends Observable implements StyleDefinition { super(); } - // private _updateCounter = 0; - // private _nativeSetters = new Map(); - public fontInternal: Font; public backgroundInternal: Background; @@ -105,199 +102,15 @@ export class Style extends Observable implements StyleDefinition { public statusBarStyle: string; public androidStatusBarBackground: Color; - effectiveMinWidth: number; - effectiveMinHeight: number; - effectiveWidth: number; - effectiveHeight: number; - effectiveMarginTop: number; - effectiveMarginRight: number; - effectiveMarginBottom: number; - effectiveMarginLeft: number; - effectivePaddingTop: number; - effectivePaddingRight: number; - effectivePaddingBottom: number; - effectivePaddingLeft: number; - effectiveBorderTopWidth: number; - effectiveBorderRightWidth: number; - effectiveBorderBottomWidth: number; - effectiveBorderLeftWidth: number; - - flexDirection: FlexDirection; - flexWrap: FlexWrap; - justifyContent: JustifyContent; - alignItems: AlignItems; - alignContent: AlignContent; - order: Order; - flexGrow: FlexGrow; - flexShrink: FlexShrink; - flexWrapBefore: FlexWrapBefore; - alignSelf: AlignSelf; - - // public _updateTextDecoration() { - // if (this.textDecoration !== TextDecoration.none) { - // this._applyProperty(textDecorationProperty, this._getValue(textDecorationProperty)); - // } - // } - - // public _updateTextTransform() { - // if (this._getValue(textTransformProperty) !== TextTransform.none) { - // this._applyProperty(textTransformProperty, this._getValue(textTransformProperty)); - // } - // } - - // public _beginUpdate() { - // this._updateCounter++; - // } - - // public _endUpdate() { - // this._updateCounter--; - // if (this._updateCounter < 0) { - // throw new Error("style._endUpdate() called, but no update is in progress."); - // } - - // if (this._updateCounter === 0) { - // this._nativeSetters.forEach((newValue, property, map) => { this._applyStyleProperty(property, newValue); }); - // this._nativeSetters.clear(); - // } - // } - - // public _resetCssValues() { - // this.view._cancelAllAnimations(); - // resetStyleProperties(this); - // } - - // public _resetLocalValues() { - // this._resetValues(ValueSource.Local); - // } - - // public _inheritStyleProperties(parent: View) { - // parent.style._eachSetPropertyValue((property, value) => { - // if (property.inheritable) { - // // this._inheritStyleProperty(property, value); - // this._setValue(property, value, ValueSource.Inherited); - // } - - // return true; - // }); - // } - - // public _onPropertyChanged(property: Property, oldValue: any, newValue: any) { - // if (traceEnabled()) { - // traceWrite( - // "Style._onPropertyChanged view:" + this._view + - // ", property: " + property.name + - // ", oldValue: " + oldValue + - // ", newValue: " + newValue, traceCategories.Style); - // } - - // super._onPropertyChanged(property, oldValue, newValue); - - // this._view._checkMetadataOnPropertyChanged(property.metadata); - - // this._applyProperty(property, newValue); - // } - - // public _sizeChanged() { - // if (!this.backgroundInternal.isEmpty()) { - // this._applyStyleProperty(backgroundInternalProperty, this.backgroundInternal); - // } - - // let clipPathPropertyValue = this.clipPath; - // if (types.isString(clipPathPropertyValue) && clipPathPropertyValue !== "") { - // this._applyStyleProperty(clipPathProperty, clipPathPropertyValue); - // } - // } - - // public _syncNativeProperties() { - // this._eachSetPropertyValue((property, value) => { - // this._applyStyleProperty(property, value); - // return true; - // }); - // } - - // private _applyProperty(property: Property, newValue: any) { - // this._applyStyleProperty(property, newValue); - - // // The effective value of an inheritable property has changed - // // propagate the change down to the descendants to update their inherited properties. - // if (property.inheritable && this._view._childrenCount > 0) { - // this._view._eachChildView((child: View) => { - // // child.style._inheritStyleProperty(property); - // child.style._setValue(property, newValue, ValueSource.Inherited); - // return true; - // }); - // } - // } - - // private _applyStyleProperty(property: Property, newValue: any) { - // if (!this._view._shouldApplyStyleHandlers()) { - // return; - // } - - // if (this._updateCounter > 0) { - // this._nativeSetters.set(property, newValue); - // return; - // } - - // let handler: definition.StylePropertyChangedHandler = getHandler(property, this._view); - // if (!handler) { - // if (traceEnabled()) { - // traceWrite("No handler for property: " + property.name + " with id: " + property.id + ", view:" + this._view, traceCategories.Style); - // } - // } - // else { - // if (traceEnabled()) { - // traceWrite("Found handler for property: " + property.name + ", view:" + this._view, traceCategories.Style); - // } - - // let shouldReset = false; - // if (property.equalityComparer) { - // shouldReset = property.equalityComparer(newValue, property.defaultValue); - // } - // else { - // shouldReset = (newValue === property.defaultValue); - // } - - // public _updateTextDecoration() { - // if (this._getValue(textDecorationProperty) !== enums.TextDecoration.none) { - // this._applyProperty(textDecorationProperty, this._getValue(textDecorationProperty)); - // } - // } - - // this._view._onStylePropertyChanged(property); - // } - // } - - // get _nativeView(): any { - // return this._view._nativeView; - // } - - // private _setShorthandProperty(name: string, value: any): void { - // let pairs = styleProperty.getShorthandPairs(name, value); - // if (pairs) { - // this._beginUpdate(); - // for (let j = 0; j < pairs.length; j++) { - // let pair = pairs[j]; - // this._setValue(pair.property, pair.value, ValueSource.Local); - // } - // this._endUpdate(); - // } - // } -} - -Style.prototype.effectiveMinWidth = 0; -Style.prototype.effectiveMinHeight = 0; -Style.prototype.effectiveWidth = 0; -Style.prototype.effectiveHeight = 0; -Style.prototype.effectiveMarginTop = 0; -Style.prototype.effectiveMarginRight = 0; -Style.prototype.effectiveMarginBottom = 0; -Style.prototype.effectiveMarginLeft = 0; -Style.prototype.effectivePaddingTop = 0; -Style.prototype.effectivePaddingRight = 0; -Style.prototype.effectivePaddingBottom = 0; -Style.prototype.effectivePaddingLeft = 0; -Style.prototype.effectiveBorderTopWidth = 0; -Style.prototype.effectiveBorderRightWidth = 0; -Style.prototype.effectiveBorderBottomWidth = 0; -Style.prototype.effectiveBorderLeftWidth = 0; + //flexbox layout properties + public flexDirection: FlexDirection; + public flexWrap: FlexWrap; + public justifyContent: JustifyContent; + public alignItems: AlignItems; + public alignContent: AlignContent; + public order: Order; + public flexGrow: FlexGrow; + public flexShrink: FlexShrink; + public flexWrapBefore: FlexWrapBefore; + public alignSelf: AlignSelf; +} \ No newline at end of file diff --git a/tns-core-modules/ui/switch/switch.ios.ts b/tns-core-modules/ui/switch/switch.ios.ts index b5affcf8d8..594d1a385b 100644 --- a/tns-core-modules/ui/switch/switch.ios.ts +++ b/tns-core-modules/ui/switch/switch.ios.ts @@ -26,6 +26,7 @@ class SwitchChangeHandlerImpl extends NSObject { }; } +const zeroSize = { width: 0, height: 0 }; export class Switch extends SwitchBase { private _ios: UISwitch; private _handler: NSObject; @@ -52,12 +53,12 @@ export class Switch extends SwitchBase { public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void { // It can't be anything different from 51x31 - let nativeSize = this._nativeView.sizeThatFits(CGSizeMake(0, 0)); + let nativeSize = this._nativeView.sizeThatFits(zeroSize); this.width = nativeSize.width; this.height = nativeSize.height; - let widthAndState = layout.makeMeasureSpec(layout.toDevicePixels(nativeSize.width), layout.EXACTLY); - let heightAndState = layout.makeMeasureSpec(layout.toDevicePixels(nativeSize.height), layout.EXACTLY); + const widthAndState = Switch.resolveSizeAndState(layout.toDevicePixels(nativeSize.width), 51, layout.EXACTLY, 0); + const heightAndState = Switch.resolveSizeAndState(layout.toDevicePixels(nativeSize.height), 31, layout.EXACTLY, 0); this.setMeasuredDimension(widthAndState, heightAndState); } diff --git a/tns-core-modules/ui/tab-view/tab-view.ios.ts b/tns-core-modules/ui/tab-view/tab-view.ios.ts index 1463fa5cfe..abe8c07cd3 100644 --- a/tns-core-modules/ui/tab-view/tab-view.ios.ts +++ b/tns-core-modules/ui/tab-view/tab-view.ios.ts @@ -287,7 +287,7 @@ export class TabView extends TabViewBase { if (!iconSource) { return null; } - + let image: UIImage = this._iconsCache[iconSource]; if (!image) { const is = fromFileOrResource(iconSource); @@ -311,9 +311,9 @@ export class TabView extends TabViewBase { const height = layout.getMeasureSpecSize(heightMeasureSpec); const heightMode = layout.getMeasureSpecMode(heightMeasureSpec); - this._tabBarHeight = TabView.measureHelper(this._ios.tabBar, width, widthMode, height, heightMode).height; + this._tabBarHeight = layout.measureNativeView(this._ios.tabBar, width, widthMode, height, heightMode).height; const moreNavBarVisible = !!this._ios.moreNavigationController.navigationBar.window; - this._navBarHeight = moreNavBarVisible ? TabView.measureHelper(this._ios.moreNavigationController.navigationBar, width, widthMode, height, heightMode).height : 0; + this._navBarHeight = moreNavBarVisible ? layout.measureNativeView(this._ios.moreNavigationController.navigationBar, width, widthMode, height, heightMode).height : 0; const density = layout.getDisplayDensity(); let measureWidth = 0; @@ -347,13 +347,6 @@ export class TabView extends TabViewBase { } } - private static measureHelper(nativeView: UIView, width: number, widthMode: number, height: number, heightMode: number): CGSize { - const size = nativeView.sizeThatFits(CGSizeMake( - (widthMode === layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : width, - (heightMode === layout.UNSPECIFIED) ? Number.POSITIVE_INFINITY : height)); - return { width: layout.toDevicePixels(size.width), height: layout.toDevicePixels(size.height) }; - } - private _updateIOSTabBarColorsAndFonts(): void { if (!this.items) { return; @@ -460,7 +453,7 @@ interface TabStates { } function getTitleAttributesForStates(tabView: TabView): TabStates { - const result: TabStates = { }; + const result: TabStates = {}; const font = tabView.style.fontInternal.getUIFont(UIFont.systemFontOfSize(10)); let tabItemTextColor = tabView.style.tabTextColor; diff --git a/tns-core-modules/ui/text-base/text-base-common.ts b/tns-core-modules/ui/text-base/text-base-common.ts index 97b35f8993..da2a2c2d8a 100644 --- a/tns-core-modules/ui/text-base/text-base-common.ts +++ b/tns-core-modules/ui/text-base/text-base-common.ts @@ -245,6 +245,7 @@ export namespace WhiteSpace { export const whiteSpaceProperty = new CssProperty({ name: "whiteSpace", cssName: "white-space", + affectsLayout: isIOS, valueConverter: WhiteSpace.parse }); whiteSpaceProperty.register(Style); diff --git a/tns-core-modules/utils/utils-common.ts b/tns-core-modules/utils/utils-common.ts index ccfe03b796..ef8a8efd4f 100644 --- a/tns-core-modules/utils/utils-common.ts +++ b/tns-core-modules/utils/utils-common.ts @@ -87,6 +87,18 @@ export module layout { text += size; return text; } + + export function round(value: number): number { + const res = Math.floor(value + 0.5); + if (res !== 0) { + return res; + } else if (value === 0) { + return 0; + } else if (value > 0) { + return 1; + } + return -1; + } } export function isFileOrResourcePath(path: string): boolean { @@ -123,7 +135,7 @@ export function mergeSort(arr, compareFunc) { export function merge(left, right, compareFunc) { let result = []; - while(left.length && right.length) { + while (left.length && right.length) { if (compareFunc(left[0], right[0]) <= 0) { result.push(left.shift()); } else { diff --git a/tns-core-modules/utils/utils.android.ts b/tns-core-modules/utils/utils.android.ts index 7e890164de..25445e42b5 100644 --- a/tns-core-modules/utils/utils.android.ts +++ b/tns-core-modules/utils/utils.android.ts @@ -45,6 +45,15 @@ export module layout { export function toDeviceIndependentPixels(value: number): number { return value / getDisplayDensity(); } + + export function measureNativeView(nativeView: any /* android.view.View */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number } { + const view = nativeView; + view.measure(makeMeasureSpec(width, widthMode), makeMeasureSpec(height, heightMode)); + return { + width: view.getMeasuredWidth(), + height: view.getMeasuredHeight() + }; + } } // We are using "ad" here to avoid namespace collision with the global android object diff --git a/tns-core-modules/utils/utils.d.ts b/tns-core-modules/utils/utils.d.ts index a0d2906ecf..a807817228 100644 --- a/tns-core-modules/utils/utils.d.ts +++ b/tns-core-modules/utils/utils.d.ts @@ -23,6 +23,9 @@ interface CacheLayerType { * Utility module related to layout. */ export module layout { + export type px = number; + export type dip = number; + /** * Bits that provide the actual measured size. */ @@ -53,7 +56,7 @@ export module layout { * @param size - The size component of measure specification. * @param mode - The mode component of measure specification. */ - export function makeMeasureSpec(size: number, mode: number): number; + export function makeMeasureSpec(px: number, mode: number): number; /** * Gets display density for the current device. */ @@ -62,13 +65,34 @@ export module layout { * Convert value to device pixels. * @param value - The pixel to convert. */ - export function toDevicePixels(value: number): number; + export function toDevicePixels(value: dip): px; /** * Convert value to device independent pixels. * @param value - The pixel to convert. */ - export function toDeviceIndependentPixels(value: number): number; + export function toDeviceIndependentPixels(value: px): dip; + /** + * Rounds value used in layout. + * @param value to round. + */ + export function round(px: px): px; + + /** + * Converts device pixels to device independent pixes and measure the nativeView. + * Returns the desired size of the nativeView in device pixels. + * @param nativeView the nativeView to measure (UIView or android.view.View) + * @param width the available width + * @param widthMode width mode - UNSPECIFIED, EXACTLY or AT_MOST + * @param height the available hegiht + * @param heightMode height mode - UNSPECIFIED, EXACTLY or AT_MOST + */ + export function measureNativeView(nativeView: any /* UIView or android.view.View */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number }; + + /** + * Prints user friendly version of the measureSpec. + * @param measureSpec the spec to print + */ export function measureSpecToString(measureSpec: number): string; } diff --git a/tns-core-modules/utils/utils.ios.ts b/tns-core-modules/utils/utils.ios.ts index 42dcf5c747..1439ddca67 100644 --- a/tns-core-modules/utils/utils.ios.ts +++ b/tns-core-modules/utils/utils.ios.ts @@ -30,6 +30,18 @@ export module layout { export function toDeviceIndependentPixels(value: number): number { return value / mainScreenScale; } + + export function measureNativeView(nativeView: any /* UIView */, width: number, widthMode: number, height: number, heightMode: number): { width: number, height: number } { + const view = nativeView; + const nativeSize = view.sizeThatFits({ + width: widthMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : toDeviceIndependentPixels(width), + height: heightMode === 0 /* layout.UNSPECIFIED */ ? Number.POSITIVE_INFINITY : toDeviceIndependentPixels(height) + }); + + nativeSize.width = toDevicePixels(nativeSize.width); + nativeSize.height = toDevicePixels(nativeSize.height); + return nativeSize; + } } export module ios { From 39bf2cf37069eefd4513f584e66ab95292949a07 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Mon, 20 Mar 2017 15:39:12 +0200 Subject: [PATCH 2/2] Fix switch measure routine --- tns-core-modules/ui/switch/switch.ios.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tns-core-modules/ui/switch/switch.ios.ts b/tns-core-modules/ui/switch/switch.ios.ts index 594d1a385b..9d4eae3ace 100644 --- a/tns-core-modules/ui/switch/switch.ios.ts +++ b/tns-core-modules/ui/switch/switch.ios.ts @@ -57,8 +57,8 @@ export class Switch extends SwitchBase { this.width = nativeSize.width; this.height = nativeSize.height; - const widthAndState = Switch.resolveSizeAndState(layout.toDevicePixels(nativeSize.width), 51, layout.EXACTLY, 0); - const heightAndState = Switch.resolveSizeAndState(layout.toDevicePixels(nativeSize.height), 31, layout.EXACTLY, 0); + const widthAndState = Switch.resolveSizeAndState(layout.toDevicePixels(nativeSize.width), layout.toDevicePixels(51), layout.EXACTLY, 0); + const heightAndState = Switch.resolveSizeAndState(layout.toDevicePixels(nativeSize.height), layout.toDevicePixels(31), layout.EXACTLY, 0); this.setMeasuredDimension(widthAndState, heightAndState); }