diff --git a/tests/app/testRunner.ts b/tests/app/testRunner.ts index ede2c8fe7..e61daea3b 100644 --- a/tests/app/testRunner.ts +++ b/tests/app/testRunner.ts @@ -62,7 +62,7 @@ allTests["WRAPLAYOUT"] = require("./ui/layouts/wrap-layout-tests"); allTests["ABSOLUTELAYOUT"] = require("./ui/layouts/absolute-layout-tests"); allTests["GRIDLAYOUT"] = require("./ui/layouts/grid-layout-tests"); allTests["STACKLAYOUT"] = require("./ui/layouts/stack-layout-tests"); -// allTests["FLEXBOXLAYOUT"] = require("./ui/layouts/flexbox-layout-tests"); +allTests["FLEXBOXLAYOUT"] = require("./ui/layouts/flexbox-layout-tests"); // allTests["STYLE-PROPERTIES"] = require("./ui/styling/style-properties-tests"); // allTests["FRAME"] = require("./ui/frame/frame-tests"); // allTests["VIEW"] = require("./ui/view/view-tests"); diff --git a/tns-core-modules/ui/core/view-common.ts b/tns-core-modules/ui/core/view-common.ts index 935a39d18..c15998005 100644 --- a/tns-core-modules/ui/core/view-common.ts +++ b/tns-core-modules/ui/core/view-common.ts @@ -12,6 +12,9 @@ import { observe as gestureObserve, GesturesObserver, GestureTypes, GestureEvent import { Font, parseFont, FontStyle, FontWeight } from "ui/styling/font"; import { fontSizeConverter } from "../styling/converters"; +// Only types: +import { Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf } from "ui/layouts/flexbox-layout" + // TODO: Remove this and start using string as source (for android). import { fromFileOrResource, fromBase64, fromUrl } from "image-source"; import { isDataURI, isFileOrResourcePath, layout } from "utils/utils"; @@ -61,6 +64,12 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { rowSpan: number; colSpan: number; + order: Order; + flexGrow: FlexGrow; + flexShrink: FlexShrink; + flexWrapBefore: FlexWrapBefore; + alignSelf: AlignSelf; + public static loadedEvent = "loaded"; public static unloadedEvent = "unloaded"; @@ -69,10 +78,14 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { _currentWidthMeasureSpec: number; _currentHeightMeasureSpec: number; - private _oldLeft: number; - private _oldTop: number; - private _oldRight: number; - private _oldBottom: number; + + _oldLeft: number; + _oldTop: number; + _oldRight: number; + _oldBottom: number; + + _minWidthNative: Length; + _minHeightNative: Length; private _isLayoutValid: boolean; private _cssType: string; @@ -662,14 +675,13 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { let measureHeight = 0; if (child && !child.isCollapsed) { - let density = layout.getDisplayDensity(); let width = layout.getMeasureSpecSize(widthMeasureSpec); let widthMode = layout.getMeasureSpecMode(widthMeasureSpec); let height = layout.getMeasureSpecSize(heightMeasureSpec); let heightMode = layout.getMeasureSpecMode(heightMeasureSpec); - updateChildLayoutParams(child, parent, density); + child._updateEffectiveLayoutValues(parent); let style = child.style; let horizontalMargins = child.effectiveMarginLeft + child.effectiveMarginRight; @@ -871,8 +883,36 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { public _setValue(): never { throw new Error("The View._setValue is obsolete. There is a new property system.") } + + _updateEffectiveLayoutValues(parent: ViewDefinition): void { + const density = layout.getDisplayDensity(); + 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; + + this.effectiveWidth = PercentLength.toDevicePixels(style.width, -2, parentAvailableWidth) + this.effectiveMarginLeft = PercentLength.toDevicePixels(style.marginLeft, 0, parentAvailableWidth); + this.effectiveMarginRight = PercentLength.toDevicePixels(style.marginRight, 0, parentAvailableWidth); + + let parentHeightMeasureSpec = parent._currentHeightMeasureSpec; + let parentHeightMeasureSize = layout.getMeasureSpecSize(parentHeightMeasureSpec); + let parentHeightMeasureMode = layout.getMeasureSpecMode(parentHeightMeasureSpec); + let parentAvailableHeight = 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); + } } +ViewCommon.prototype._oldLeft = 0; +ViewCommon.prototype._oldTop = 0; +ViewCommon.prototype._oldRight = 0; +ViewCommon.prototype._oldBottom = 0; + ViewCommon.prototype.effectiveMinWidth = 0; ViewCommon.prototype.effectiveMinHeight = 0; ViewCommon.prototype.effectiveWidth = 0; @@ -890,28 +930,6 @@ ViewCommon.prototype.effectiveBorderRightWidth = 0; ViewCommon.prototype.effectiveBorderBottomWidth = 0; ViewCommon.prototype.effectiveBorderLeftWidth = 0; -function updateChildLayoutParams(child: ViewCommon, parent: ViewCommon, density: number): void { - let style = child.style; - - let parentWidthMeasureSpec = parent._currentWidthMeasureSpec; - let parentWidthMeasureSize = layout.getMeasureSpecSize(parentWidthMeasureSpec); - let parentWidthMeasureMode = layout.getMeasureSpecMode(parentWidthMeasureSpec); - let parentAvailableWidth = parentWidthMeasureMode === layout.UNSPECIFIED ? -1 : parentWidthMeasureSize; - - child.effectiveWidth = PercentLength.toDevicePixels(style.width, -2, parentAvailableWidth) - child.effectiveMarginLeft = PercentLength.toDevicePixels(style.marginLeft, 0, parentAvailableWidth); - child.effectiveMarginRight = PercentLength.toDevicePixels(style.marginRight, 0, parentAvailableWidth); - - let parentHeightMeasureSpec = parent._currentHeightMeasureSpec; - let parentHeightMeasureSize = layout.getMeasureSpecSize(parentHeightMeasureSpec); - let parentHeightMeasureMode = layout.getMeasureSpecMode(parentHeightMeasureSpec); - let parentAvailableHeight = parentHeightMeasureMode === layout.UNSPECIFIED ? -1 : parentHeightMeasureSize; - - child.effectiveHeight = PercentLength.toDevicePixels(style.height, -2, parentAvailableHeight); - child.effectiveMarginTop = PercentLength.toDevicePixels(style.marginTop, 0, parentAvailableHeight); - child.effectiveMarginBottom = PercentLength.toDevicePixels(style.marginBottom, 0, parentAvailableHeight); -} - function equalsCommon(a: Length, b: Length): boolean; function equalsCommon(a: PercentLength, b: PercentLength): boolean; function equalsCommon(a: PercentLength, b: PercentLength): boolean { diff --git a/tns-core-modules/ui/core/view.android.ts b/tns-core-modules/ui/core/view.android.ts index 809b2155b..5db5c08af 100644 --- a/tns-core-modules/ui/core/view.android.ts +++ b/tns-core-modules/ui/core/view.android.ts @@ -1,7 +1,8 @@ import { PercentLength, Point, CustomLayoutView as CustomLayoutViewDefinition } from "ui/core/view"; import { ad as androidBackground } from "ui/styling/background"; import { - ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty, visibilityProperty, opacityProperty, minWidthProperty, minHeightProperty, + ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty, visibilityProperty, opacityProperty, + minWidthProperty, minHeightProperty, Length, widthProperty, heightProperty, marginLeftProperty, marginTopProperty, marginRightProperty, marginBottomProperty, horizontalAlignmentProperty, verticalAlignmentProperty, rotateProperty, scaleXProperty, scaleYProperty, @@ -447,6 +448,22 @@ export class View extends ViewCommon { androidBackground.onBackgroundOrBorderPropertyChanged(this); } } + + set [minWidthProperty.native](value: Length) { + if (this.parent instanceof CustomLayoutView && this.parent.nativeView) { + this.parent._setChildMinWidthNative(this); + } else { + this._minWidthNative = this.minWidth; + } + } + + set [minHeightProperty.native](value: Length) { + if (this.parent instanceof CustomLayoutView && this.parent.nativeView) { + this.parent._setChildMinHeightNative(this); + } else { + this._minHeightNative = this.minHeight; + } + } } type NativeSetter = { (view: android.view.View, value: number): void }; @@ -534,13 +551,13 @@ createNativePercentLengthProperty({ }); createNativePercentLengthProperty({ - key: minWidthProperty.native, + key: "_minWidthNative", getPixels: ViewHelper.getMinWidth, setPixels: ViewHelper.setMinWidth }); createNativePercentLengthProperty({ - key: minHeightProperty.native, + key: "_minHeightNative", getPixels: ViewHelper.getMinHeight, setPixels: ViewHelper.setMinHeight }); @@ -568,12 +585,28 @@ export class CustomLayoutView extends View implements CustomLayoutViewDefinition traceWrite(`${this}.nativeView.addView(${child}.nativeView, ${atIndex})`, traceCategories.VisualTreeEvents); } this._nativeView.addView(child.nativeView, atIndex); + if (child instanceof View) { + this._updateNativeLayoutParams(child); + } return true; } return false; } + public _updateNativeLayoutParams(child: View): void { + this._setChildMinWidthNative(child); + this._setChildMinHeightNative(child); + } + + public _setChildMinWidthNative(child: View): void { + child._minWidthNative = child.minWidth; + } + + public _setChildMinHeightNative(child: View): void { + child._minHeightNative = child.minHeight; + } + public _removeViewFromNativeVisualTree(child: ViewCommon): void { super._removeViewFromNativeVisualTree(child); diff --git a/tns-core-modules/ui/core/view.d.ts b/tns-core-modules/ui/core/view.d.ts index 60191a9eb..095674e10 100644 --- a/tns-core-modules/ui/core/view.d.ts +++ b/tns-core-modules/ui/core/view.d.ts @@ -569,6 +569,14 @@ declare module "ui/core/view" { _nativeView: any; _setNativeViewFrame(nativeView: any, frame: any): void; // _onStylePropertyChanged(property: dependencyObservable.Property): void; + + _updateEffectiveLayoutValues(parent: View): void; + + _currentWidthMeasureSpec: number; + _currentHeightMeasureSpec: number; + + _minWidthNative: Length; + _minHeightNative: Length; //@endprivate public effectiveMinWidth: number; @@ -603,6 +611,11 @@ declare module "ui/core/view" { * Base class for all UI components that implements custom layouts. */ export class CustomLayoutView extends View { + //@private + _updateNativeLayoutParams(child: View): void; + _setChildMinWidthNative(child: View): void; + _setChildMinHeightNative(child: View): void; + //@endprivate } /** diff --git a/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout-common.ts b/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout-common.ts index 475abd561..32a5d119e 100644 --- a/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout-common.ts +++ b/tns-core-modules/ui/layouts/flexbox-layout/flexbox-layout-common.ts @@ -231,7 +231,7 @@ export abstract class FlexboxLayoutBase extends LayoutBase { export const flexDirectionProperty = new CssProperty({ name: "flexDirection", cssName: "flex-direction", defaultValue: FlexDirection.ROW, affectsLayout: isIOS, valueConverter: FlexDirection.parse }); flexDirectionProperty.register(Style); -export const flexWrapProperty = new CssProperty({ name: "flexWrap", cssName: "flex-wrap", defaultValue: FlexWrap.NOWRAP, affectsLayout: isIOS, valueConverter: FlexWrap.parse }); +export const flexWrapProperty = new CssProperty({ name: "flexWrap", cssName: "flex-wrap", defaultValue: "nowrap", affectsLayout: isIOS, valueConverter: FlexWrap.parse }); flexWrapProperty.register(Style); export const justifyContentProperty = new CssProperty({ name: "justifyContent", cssName: "justify-content", defaultValue: JustifyContent.FLEX_START, affectsLayout: isIOS, valueConverter: JustifyContent.parse }); @@ -245,84 +245,68 @@ alignContentProperty.register(Style); export const orderProperty = new CssProperty({ name: "order", cssName: "order", defaultValue: ORDER_DEFAULT, valueConverter: Order.parse }); orderProperty.register(Style); +Object.defineProperty(View.prototype, "order", { + get(this: View): Order { + return this.style.order; + }, + set(this: View, value: Order) { + this.style.order = value; + }, + enumerable: true, + configurable: true +}); export const flexGrowProperty = new CssProperty({ name: "flexGrow", cssName: "flex-grow", defaultValue: FLEX_GROW_DEFAULT, valueConverter: FlexGrow.parse }); flexGrowProperty.register(Style); +Object.defineProperty(View.prototype, "flexGrow", { + get(this: View): FlexGrow { + return this.style.flexGrow; + }, + set(this: View, value: FlexGrow) { + this.style.flexGrow = value; + }, + enumerable: true, + configurable: true +}); export const flexShrinkProperty = new CssProperty({ name: "flexShrink", cssName: "flex-shrink", defaultValue: FLEX_SHRINK_DEFAULT, valueConverter: FlexShrink.parse }); flexShrinkProperty.register(Style); +Object.defineProperty(View.prototype, "flexShrink", { + get(this: View): FlexShrink { + return this.style.flexShrink; + }, + set(this: View, value: FlexShrink) { + this.style.flexShrink = value; + }, + enumerable: true, + configurable: true +}); export const flexWrapBeforeProperty = new CssProperty({ name: "flexWrapBefore", cssName: "flex-wrap-before", defaultValue: false, valueConverter: FlexWrapBefore.parse }); flexWrapBeforeProperty.register(Style); +Object.defineProperty(View.prototype, "flexWrapBefore", { + get(this: View): FlexWrapBefore { + return this.style.flexWrapBefore; + }, + set(this: View, value: FlexWrapBefore) { + this.style.flexWrapBefore = value; + }, + enumerable: true, + configurable: true +}); export const alignSelfProperty = new CssProperty({ name: "alignSelf", cssName: "align-self", defaultValue: AlignSelf.AUTO, valueConverter: AlignSelf.parse }); alignSelfProperty.register(Style); - -// These support setting attached properties through XML. Delete if we stop supporting them. -// they could be set in XML through style --