Fix a crash when nesting a ProxyViewContainer in FlexboxLayout.

This commit is contained in:
Hristo Deshev
2017-02-21 15:09:28 +02:00
committed by Hristo Deshev
parent e0b0e46f70
commit 18739f8cd1
2 changed files with 47 additions and 9 deletions

View File

@@ -1975,6 +1975,20 @@ export const testWrap_childMargin_vertical = test(
} }
); );
let activity_flexbox_with_proxy_view_container = () => getViews(
`<FlexboxLayout id="flexbox">
<ProxyViewContainer></ProxyViewContainer>
</FlexboxLayout>`
);
export const testFlexboxLayout_does_not_crash_with_proxy_view_container = test(
activity_flexbox_with_proxy_view_container,
noop,
({root, flexbox}) => {
TKUnit.assert(flexbox.id === "flexbox", "FlexboxLayout actually there");
}
);
// Omit testEmptyChildren // Omit testEmptyChildren
// Omit testDivider_directionRow_verticalBeginning // Omit testDivider_directionRow_verticalBeginning

View File

@@ -67,6 +67,28 @@ import makeMeasureSpec = utils.layout.makeMeasureSpec;
import getMeasureSpecMode = utils.layout.getMeasureSpecMode; import getMeasureSpecMode = utils.layout.getMeasureSpecMode;
import getMeasureSpecSize = utils.layout.getMeasureSpecSize; import getMeasureSpecSize = utils.layout.getMeasureSpecSize;
// `eachLayoutChild` iterates over children, and we need more - indexed access.
// This class tries to accomodate that by collecting all children in an
// array no more than once per measure.
class MeasureContext {
private children: View[];
constructor(private owner: FlexboxLayout) {
this.children = [];
this.owner.eachLayoutChild((child) => {
this.children.push(child);
});
}
public get childrenCount(): number {
return this.children.length;
}
public childAt(index: number): View {
return this.children[index];
}
}
class FlexLine { class FlexLine {
_left: number = Number.MAX_VALUE; _left: number = Number.MAX_VALUE;
@@ -117,6 +139,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
private _orderCache: number[]; private _orderCache: number[];
private _flexLines: FlexLine[] = []; private _flexLines: FlexLine[] = [];
private _childrenFrozen: boolean[]; private _childrenFrozen: boolean[];
private measureContext: MeasureContext;
_setNativeFlexDirection(flexDirection: FlexDirection) { _setNativeFlexDirection(flexDirection: FlexDirection) {
// lint happy no-op // lint happy no-op
@@ -141,6 +164,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
} }
public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void { public onMeasure(widthMeasureSpec: number, heightMeasureSpec: number): void {
this.measureContext = new MeasureContext(this);
LayoutBase.adjustChildrenLayoutParams(this, widthMeasureSpec, heightMeasureSpec); LayoutBase.adjustChildrenLayoutParams(this, widthMeasureSpec, heightMeasureSpec);
// Omit: super.onMeasure(widthMeasureSpec, heightMeasureSpec); // Omit: super.onMeasure(widthMeasureSpec, heightMeasureSpec);
@@ -148,8 +172,8 @@ export class FlexboxLayout extends FlexboxLayoutBase {
if (this._isOrderChangedFromLastMeasurement) { if (this._isOrderChangedFromLastMeasurement) {
this._reorderedIndices = this._createReorderedIndices(); this._reorderedIndices = this._createReorderedIndices();
} }
if (!this._childrenFrozen || this._childrenFrozen.length < this.getChildrenCount()) { if (!this._childrenFrozen || this._childrenFrozen.length < this.measureContext.childrenCount) {
this._childrenFrozen = new Array(this.getChildrenCount()); this._childrenFrozen = new Array(this.measureContext.childrenCount);
} }
switch (this.flexDirection) { switch (this.flexDirection) {
@@ -174,13 +198,13 @@ export class FlexboxLayout extends FlexboxLayoutBase {
child = null; child = null;
} else { } else {
let reorderedIndex = this._reorderedIndices[index]; let reorderedIndex = this._reorderedIndices[index];
child = this.getChildAt(reorderedIndex); child = this.measureContext.childAt(reorderedIndex);
} }
return child; return child;
} }
private _createReorderedIndices(): number[] { private _createReorderedIndices(): number[] {
let childCount = this.getChildrenCount(); let childCount = this.measureContext.childrenCount;
let orders = this._createOrders(childCount); let orders = this._createOrders(childCount);
return this._sortOrdersIntoReorderedIndices(childCount, orders); return this._sortOrdersIntoReorderedIndices(childCount, orders);
} }
@@ -203,7 +227,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
private _createOrders(childCount: number): Order[] { private _createOrders(childCount: number): Order[] {
let orders: Order[] = []; let orders: Order[] = [];
for (let i = 0; i < childCount; i++) { for (let i = 0; i < childCount; i++) {
let child = this.getChildAt(i); let child = this.measureContext.childAt(i);
let order = new Order(); let order = new Order();
order.order = FlexboxLayout.getOrder(child); order.order = FlexboxLayout.getOrder(child);
order.index = i; order.index = i;
@@ -213,7 +237,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
} }
private get _isOrderChangedFromLastMeasurement(): boolean { private get _isOrderChangedFromLastMeasurement(): boolean {
let childCount = this.getChildrenCount(); let childCount = this.measureContext.childrenCount;
if (!this._orderCache) { if (!this._orderCache) {
this._orderCache = []; this._orderCache = [];
} }
@@ -221,7 +245,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
return true; return true;
} }
for (let i = 0; i < childCount; i++) { for (let i = 0; i < childCount; i++) {
let view = this.getChildAt(i); let view = this.measureContext.childAt(i);
if (view === null) { if (view === null) {
continue; continue;
} }
@@ -241,7 +265,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
this._flexLines.length = 0; this._flexLines.length = 0;
(() => { (() => {
let childCount = this.getChildrenCount(); let childCount = this.measureContext.childrenCount;
let paddingStart = FlexboxLayout.getPaddingStart(this); let paddingStart = FlexboxLayout.getPaddingStart(this);
let paddingEnd = FlexboxLayout.getPaddingEnd(this); let paddingEnd = FlexboxLayout.getPaddingEnd(this);
let largestHeightInRow = Number.MIN_VALUE; let largestHeightInRow = Number.MIN_VALUE;
@@ -355,7 +379,7 @@ export class FlexboxLayout extends FlexboxLayoutBase {
this._flexLines.length = 0; this._flexLines.length = 0;
let childCount = this.getChildrenCount(); let childCount = this.measureContext.childrenCount;
let paddingTop = this.paddingTop; let paddingTop = this.paddingTop;
let paddingBottom = this.paddingBottom; let paddingBottom = this.paddingBottom;
let largestWidthInColumn = Number.MIN_VALUE; let largestWidthInColumn = Number.MIN_VALUE;