mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
perf(android): gridlayout with less JNI calls (#10402)
This commit is contained in:
@@ -16,15 +16,31 @@ class RemovalTrackingGridLayout extends GridLayout {
|
||||
public removedRows = 0;
|
||||
public removedCols = 0;
|
||||
|
||||
// this trick wont work on android anymore as removeRows
|
||||
// is done in one call and does not go through _onRowRemoved
|
||||
public _onRowRemoved(itemSpec: ItemSpec, index: number) {
|
||||
this.removedRows++;
|
||||
super._onRowRemoved(itemSpec, index);
|
||||
}
|
||||
|
||||
// this trick wont work on android anymore as removeColumns
|
||||
// is done in one call and does not go through _onColumnRemoved
|
||||
public _onColumnRemoved(itemSpec: ItemSpec, index: number) {
|
||||
this.removedCols++;
|
||||
super._onColumnRemoved(itemSpec, index);
|
||||
}
|
||||
public removeRows() {
|
||||
if (__ANDROID__) {
|
||||
this.removedRows = this.getRows().length;
|
||||
}
|
||||
super.removeRows();
|
||||
}
|
||||
public removeColumns() {
|
||||
if (__ANDROID__) {
|
||||
this.removedCols = this.getColumns().length;
|
||||
}
|
||||
super.removeColumns();
|
||||
}
|
||||
}
|
||||
|
||||
export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout> {
|
||||
@@ -39,7 +55,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
public test_item_recycling() {
|
||||
helper.nativeView_recycling_test(
|
||||
() => new Button(),
|
||||
() => new GridLayout()
|
||||
() => new GridLayout(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -350,6 +366,21 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
TKUnit.assertTrue(this.testView.getMeasuredWidth() < platform.Screen.mainScreen.widthPixels);
|
||||
}
|
||||
|
||||
private getGridLayoutRowActualLength(view: GridLayout, index: number) {
|
||||
if (__ANDROID__) {
|
||||
return Math.round(layoutHelper.dp(view.nativeViewProtected.getRowActualLength(index)));
|
||||
} else {
|
||||
return view.getRows()[index].actualLength;
|
||||
}
|
||||
}
|
||||
private getGridLayoutColumnActualLength(view: GridLayout, index: number) {
|
||||
if (__ANDROID__) {
|
||||
return Math.round(layoutHelper.dp(view.nativeViewProtected.getColumnActualLength(index)));
|
||||
} else {
|
||||
return view.getColumns()[index].actualLength;
|
||||
}
|
||||
}
|
||||
|
||||
public test_measuredWidth_when_not_stretched_two_columns() {
|
||||
this.testView.horizontalAlignment = 'center';
|
||||
this.testView.addColumn(new ItemSpec(layoutHelper.dp(80), 'pixel'));
|
||||
@@ -363,9 +394,8 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
var cols = this.testView.getColumns();
|
||||
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
|
||||
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(20)), DELTA, 'column 1');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(20)), DELTA, 'column 1');
|
||||
TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 100, DELTA, 'measured width');
|
||||
}
|
||||
|
||||
@@ -392,9 +422,9 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
var cols = this.testView.getColumns();
|
||||
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
|
||||
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(40)), DELTA, 'column 1');
|
||||
TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(60)), DELTA, 'column 2');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(80)), DELTA, 'column 0');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(40)), DELTA, 'column 1');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(60)), DELTA, 'column 2');
|
||||
TKUnit.assertAreClose(this.testView.getMeasuredWidth(), 180, DELTA, 'measured width');
|
||||
}
|
||||
|
||||
@@ -484,7 +514,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
for (var c = 0; c < 4; c++) {
|
||||
var btn = <layoutHelper.MyButton>this.testView.getChildAt(i++);
|
||||
if (cols[c].isAbsolute) {
|
||||
width += layoutHelper.dip(cols[c].actualLength);
|
||||
width += layoutHelper.dip(this.getGridLayoutColumnActualLength(this.testView, c));
|
||||
} else {
|
||||
width += btn.getMeasuredWidth();
|
||||
}
|
||||
@@ -495,7 +525,7 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
maxWidth = Math.max(maxWidth, width);
|
||||
|
||||
if (rows[r].isAbsolute) {
|
||||
maxHeight += layoutHelper.dip(rows[r].actualLength);
|
||||
maxHeight += layoutHelper.dip(this.getGridLayoutRowActualLength(this.testView, r));
|
||||
} else {
|
||||
maxHeight += height;
|
||||
}
|
||||
@@ -510,21 +540,19 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
public test_columnsActualWidth_isCorrect() {
|
||||
this.prepareGridLayout(true);
|
||||
|
||||
var cols = this.testView.getColumns();
|
||||
TKUnit.assertEqual(cols[0].actualLength, Math.round(layoutHelper.dp(50)), 'Star column should be 50px width');
|
||||
TKUnit.assertEqual(cols[1].actualLength, Math.round(layoutHelper.dp(100)), '2*Star column should be 100px width');
|
||||
TKUnit.assertEqual(cols[2].actualLength, Math.round(layoutHelper.dp(50)), 'Absolute column should be 50px width');
|
||||
TKUnit.assertEqual(cols[3].actualLength, Math.round(layoutHelper.dp(100)), 'Auto column should be 100px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(50)), 'Star column should be 50px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(100)), '2*Star column should be 100px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(50)), 'Absolute column should be 50px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutColumnActualLength(this.testView, 3), Math.round(layoutHelper.dp(100)), 'Auto column should be 100px width');
|
||||
}
|
||||
|
||||
public test_rowsActualHeight_isCorrect() {
|
||||
this.prepareGridLayout(true);
|
||||
|
||||
var rows = this.testView.getRows();
|
||||
TKUnit.assertEqual(rows[0].actualLength, Math.round(layoutHelper.dp(50)), 'Star row should be 50px width');
|
||||
TKUnit.assertEqual(rows[1].actualLength, Math.round(layoutHelper.dp(100)), '2*Star row should be 100px width');
|
||||
TKUnit.assertEqual(rows[2].actualLength, Math.round(layoutHelper.dp(50)), 'Absolute row should be 50px width');
|
||||
TKUnit.assertEqual(rows[3].actualLength, Math.round(layoutHelper.dp(100)), 'Auto row should be 100px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 0), Math.round(layoutHelper.dp(50)), 'Star row should be 50px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 1), Math.round(layoutHelper.dp(100)), '2*Star row should be 100px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 2), Math.round(layoutHelper.dp(50)), 'Absolute row should be 50px width');
|
||||
TKUnit.assertEqual(this.getGridLayoutRowActualLength(this.testView, 3), Math.round(layoutHelper.dp(100)), 'Auto row should be 100px width');
|
||||
}
|
||||
|
||||
public test_Measure_and_Layout_Children_withCorrect_size() {
|
||||
@@ -575,12 +603,10 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
var cols = this.testView.getColumns();
|
||||
|
||||
TKUnit.assertAreClose(cols[0].actualLength, Math.round(layoutHelper.dp(28)), DELTA, 'Column[0] actual length should be 28');
|
||||
TKUnit.assertAreClose(cols[1].actualLength, Math.round(layoutHelper.dp(27)), DELTA, 'Column[1] actual length should be 27');
|
||||
TKUnit.assertAreClose(cols[2].actualLength, Math.round(layoutHelper.dp(28)), DELTA, 'Column[2] actual length should be 28');
|
||||
TKUnit.assertAreClose(cols[3].actualLength, Math.round(layoutHelper.dp(27)), DELTA, 'Column[3] actual length should be 27');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 0), Math.round(layoutHelper.dp(28)), DELTA, 'Column[0] actual length should be 28');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 1), Math.round(layoutHelper.dp(27)), DELTA, 'Column[1] actual length should be 27');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 2), Math.round(layoutHelper.dp(28)), DELTA, 'Column[2] actual length should be 28');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(this.testView, 3), Math.round(layoutHelper.dp(27)), DELTA, 'Column[3] actual length should be 27');
|
||||
}
|
||||
|
||||
public test_margins_and_verticalAlignment_center() {
|
||||
@@ -799,15 +825,13 @@ export class GridLayoutTest extends testModule.UITest<RemovalTrackingGridLayout>
|
||||
GridLayout.setRowSpan(btn, 3);
|
||||
this.waitUntilTestElementLayoutIsValid();
|
||||
|
||||
var cols = grid.getColumns();
|
||||
TKUnit.assertAreClose(cols[0].actualLength, layoutHelper.dp(33), DELTA, 'Column[0] actual length should be 67');
|
||||
TKUnit.assertAreClose(cols[1].actualLength, layoutHelper.dp(100), DELTA, 'Column[1] actual length should be 100');
|
||||
TKUnit.assertAreClose(cols[2].actualLength, layoutHelper.dp(67), DELTA, 'Column[2] actual length should be 133');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 0), layoutHelper.dp(33), DELTA, 'Column[0] actual length should be 67');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 1), layoutHelper.dp(100), DELTA, 'Column[1] actual length should be 100');
|
||||
TKUnit.assertAreClose(this.getGridLayoutColumnActualLength(grid, 2), layoutHelper.dp(67), DELTA, 'Column[2] actual length should be 133');
|
||||
|
||||
var rows = grid.getRows();
|
||||
TKUnit.assertAreClose(rows[0].actualLength, layoutHelper.dp(67), DELTA, 'Row[0] actual length should be 133');
|
||||
TKUnit.assertAreClose(rows[1].actualLength, layoutHelper.dp(100), DELTA, 'Row[1] actual length should be 100');
|
||||
TKUnit.assertAreClose(rows[2].actualLength, layoutHelper.dp(133), DELTA, 'Row[2] actual length should be 267');
|
||||
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 0), layoutHelper.dp(67), DELTA, 'Row[0] actual length should be 133');
|
||||
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 1), layoutHelper.dp(100), DELTA, 'Row[1] actual length should be 100');
|
||||
TKUnit.assertAreClose(this.getGridLayoutRowActualLength(grid, 2), layoutHelper.dp(133), DELTA, 'Row[2] actual length should be 267');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -63,20 +63,23 @@ function convertGridLength(value: string): ItemSpec {
|
||||
}
|
||||
}
|
||||
|
||||
function parseAndAddItemSpecs(value: string, func: (itemSpec: ItemSpec) => void): void {
|
||||
function parseAndAddItemSpecs(value: string) {
|
||||
// ensure value is a string since view bindings could be parsed as number/int's here
|
||||
const specs: ItemSpec[] = [];
|
||||
const arr = `${value}`.split(/[\s,]+/);
|
||||
for (let i = 0, length = arr.length; i < length; i++) {
|
||||
const str = arr[i].trim();
|
||||
if (str.length > 0) {
|
||||
func(convertGridLength(arr[i].trim()));
|
||||
specs.push(convertGridLength(arr[i].trim()));
|
||||
}
|
||||
}
|
||||
return specs;
|
||||
}
|
||||
|
||||
export class ItemSpec extends Observable implements ItemSpecDefinition {
|
||||
private _value: number;
|
||||
private _unitType: GridUnitType;
|
||||
toJSON?: () => any;
|
||||
|
||||
constructor(...args) {
|
||||
super();
|
||||
@@ -147,8 +150,8 @@ export class ItemSpec extends Observable implements ItemSpecDefinition {
|
||||
|
||||
@CSSType('GridLayout')
|
||||
export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {
|
||||
private _rows: Array<ItemSpec> = new Array<ItemSpec>();
|
||||
private _cols: Array<ItemSpec> = new Array<ItemSpec>();
|
||||
protected _rows: Array<ItemSpec> = new Array<ItemSpec>();
|
||||
protected _cols: Array<ItemSpec> = new Array<ItemSpec>();
|
||||
|
||||
public static getColumn(element: View): number {
|
||||
return validateArgs(element).col;
|
||||
@@ -182,22 +185,48 @@ export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {
|
||||
validateArgs(element).rowSpan = value;
|
||||
}
|
||||
|
||||
public addRow(itemSpec: ItemSpec) {
|
||||
public _addRow(itemSpec: ItemSpec) {
|
||||
validateItemSpec(itemSpec);
|
||||
itemSpec.owner = this;
|
||||
this._rows.push(itemSpec);
|
||||
}
|
||||
|
||||
public addRow(itemSpec: ItemSpec) {
|
||||
this._addRow(itemSpec);
|
||||
this._onRowAdded(itemSpec);
|
||||
this.invalidate();
|
||||
}
|
||||
|
||||
public addColumn(itemSpec: ItemSpec) {
|
||||
public addRows(itemSpecs: ItemSpec[]) {
|
||||
for (let index = 0; index < itemSpecs.length; index++) {
|
||||
const itemSpec = itemSpecs[index];
|
||||
this._addRow(itemSpec);
|
||||
this._onRowAdded(itemSpec);
|
||||
}
|
||||
this.invalidate();
|
||||
}
|
||||
|
||||
public _addColumn(itemSpec: ItemSpec) {
|
||||
validateItemSpec(itemSpec);
|
||||
itemSpec.owner = this;
|
||||
this._cols.push(itemSpec);
|
||||
}
|
||||
|
||||
public addColumn(itemSpec: ItemSpec) {
|
||||
this._addColumn(itemSpec);
|
||||
this._onColumnAdded(itemSpec);
|
||||
this.invalidate();
|
||||
}
|
||||
|
||||
public addColumns(itemSpecs: ItemSpec[]) {
|
||||
for (let index = 0; index < itemSpecs.length; index++) {
|
||||
const itemSpec = itemSpecs[index];
|
||||
this._addColumn(itemSpec);
|
||||
this._onColumnAdded(itemSpec);
|
||||
}
|
||||
this.invalidate();
|
||||
}
|
||||
|
||||
public addChildAtCell(view: View, row: number, column: number, rowSpan?: number, columnSpan?: number): void {
|
||||
this.addChild(view);
|
||||
GridLayoutBase.setRow(view, row);
|
||||
@@ -316,12 +345,14 @@ export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition {
|
||||
|
||||
set rows(value: string) {
|
||||
this.removeRows();
|
||||
parseAndAddItemSpecs(value, (spec: ItemSpec) => this.addRow(spec));
|
||||
const specs = parseAndAddItemSpecs(value);
|
||||
this.addRows(specs);
|
||||
}
|
||||
|
||||
set columns(value: string) {
|
||||
this.removeColumns();
|
||||
parseAndAddItemSpecs(value, (spec: ItemSpec) => this.addColumn(spec));
|
||||
const specs = parseAndAddItemSpecs(value);
|
||||
this.addColumns(specs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,32 +20,26 @@ View.prototype[columnProperty.setNative] = makeNativeSetter<number>((lp, value)
|
||||
View.prototype[rowSpanProperty.setNative] = makeNativeSetter<number>((lp, value) => (lp.rowSpan = value));
|
||||
View.prototype[columnSpanProperty.setNative] = makeNativeSetter<number>((lp, value) => (lp.columnSpan = value));
|
||||
|
||||
function createNativeSpec(itemSpec: ItemSpec): org.nativescript.widgets.ItemSpec {
|
||||
switch (itemSpec.gridUnitType) {
|
||||
ItemSpecBase.prototype.toJSON = function () {
|
||||
let result;
|
||||
switch (this.gridUnitType) {
|
||||
case GridUnitType.AUTO:
|
||||
return new org.nativescript.widgets.ItemSpec(itemSpec.value, org.nativescript.widgets.GridUnitType.auto);
|
||||
|
||||
case GridUnitType.STAR:
|
||||
return new org.nativescript.widgets.ItemSpec(itemSpec.value, org.nativescript.widgets.GridUnitType.star);
|
||||
|
||||
result = { type: 0 /* org.nativescript.widgets.GridUnitType.auto */, value: this.value };
|
||||
break;
|
||||
case GridUnitType.PIXEL:
|
||||
return new org.nativescript.widgets.ItemSpec(itemSpec.value * layout.getDisplayDensity(), org.nativescript.widgets.GridUnitType.pixel);
|
||||
|
||||
result = { type: 1 /* org.nativescript.widgets.GridUnitType.pixel */, value: this.value * layout.getDisplayDensity() };
|
||||
break;
|
||||
case GridUnitType.STAR:
|
||||
result = { type: 2 /* org.nativescript.widgets.GridUnitType.star */, value: this.value };
|
||||
break;
|
||||
default:
|
||||
throw new Error('Invalid gridUnitType: ' + itemSpec.gridUnitType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export class ItemSpec extends ItemSpecBase {
|
||||
nativeSpec: org.nativescript.widgets.ItemSpec;
|
||||
|
||||
public get actualLength(): number {
|
||||
if (this.nativeSpec) {
|
||||
return Math.round(this.nativeSpec.getActualLength() / layout.getDisplayDensity());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
interface ItemSpec extends ItemSpecBase {
|
||||
toJSON(): { value: number; type: number };
|
||||
}
|
||||
|
||||
export class GridLayout extends GridLayoutBase {
|
||||
@@ -58,54 +52,86 @@ export class GridLayout extends GridLayoutBase {
|
||||
public initNativeView(): void {
|
||||
super.initNativeView();
|
||||
// Update native GridLayout
|
||||
this.rowsInternal.forEach((itemSpec: ItemSpec, index, rows) => {
|
||||
this._onRowAdded(itemSpec);
|
||||
}, this);
|
||||
this.columnsInternal.forEach((itemSpec: ItemSpec, index, rows) => {
|
||||
this._onColumnAdded(itemSpec);
|
||||
}, this);
|
||||
const jsonRows = JSON.stringify(this.rowsInternal.map((itemSpec: ItemSpec) => itemSpec.toJSON()).filter((j) => !!j));
|
||||
const jsonColumns = JSON.stringify(this.columnsInternal.map((itemSpec: ItemSpec) => itemSpec.toJSON()).filter((j) => !!j));
|
||||
this.nativeViewProtected.addRowsAndColumnsFromJSON(jsonRows, jsonColumns);
|
||||
}
|
||||
|
||||
public resetNativeView() {
|
||||
// Update native GridLayout
|
||||
for (let i = this.rowsInternal.length; i--; i >= 0) {
|
||||
const itemSpec = <ItemSpec>this.rowsInternal[i];
|
||||
this._onRowRemoved(itemSpec, i);
|
||||
}
|
||||
|
||||
for (let i = this.columnsInternal.length; i--; i >= 0) {
|
||||
const itemSpec = <ItemSpec>this.columnsInternal[i];
|
||||
this._onColumnRemoved(itemSpec, i);
|
||||
}
|
||||
|
||||
this.nativeViewProtected.reset();
|
||||
super.resetNativeView();
|
||||
}
|
||||
|
||||
public _onRowAdded(itemSpec: ItemSpec) {
|
||||
if (this.nativeViewProtected) {
|
||||
const nativeSpec = createNativeSpec(itemSpec);
|
||||
itemSpec.nativeSpec = nativeSpec;
|
||||
this.nativeViewProtected.addRow(nativeSpec);
|
||||
this.nativeViewProtected.addRowsFromJSON(JSON.stringify([itemSpec.toJSON()]));
|
||||
}
|
||||
}
|
||||
|
||||
public addRows(itemSpecs: ItemSpec[]) {
|
||||
const jsonArray = [];
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const initialized = !!nativeView;
|
||||
for (let index = 0; index < itemSpecs.length; index++) {
|
||||
const itemSpec = itemSpecs[index];
|
||||
this._addRow(itemSpec);
|
||||
if (initialized) {
|
||||
jsonArray.push(itemSpec.toJSON());
|
||||
}
|
||||
}
|
||||
if (initialized) {
|
||||
nativeView.addRowsFromJSON(JSON.stringify(jsonArray.filter((s) => !!s)));
|
||||
}
|
||||
}
|
||||
|
||||
public addColumns(itemSpecs: ItemSpec[]) {
|
||||
const jsonArray = [];
|
||||
const nativeView = this.nativeViewProtected;
|
||||
const initialized = !!nativeView;
|
||||
for (let index = 0; index < itemSpecs.length; index++) {
|
||||
const itemSpec = itemSpecs[index];
|
||||
this._addColumn(itemSpec);
|
||||
if (initialized) {
|
||||
jsonArray.push(itemSpec.toJSON());
|
||||
}
|
||||
}
|
||||
if (initialized) {
|
||||
nativeView.addColumnsFromJSON(JSON.stringify(jsonArray.filter((s) => !!s)));
|
||||
}
|
||||
}
|
||||
|
||||
public _onColumnAdded(itemSpec: ItemSpec) {
|
||||
if (this.nativeViewProtected) {
|
||||
const nativeSpec = createNativeSpec(itemSpec);
|
||||
itemSpec.nativeSpec = nativeSpec;
|
||||
this.nativeViewProtected.addColumn(nativeSpec);
|
||||
this.nativeViewProtected.addColumnsFromJSON(JSON.stringify([itemSpec.toJSON()]));
|
||||
}
|
||||
}
|
||||
|
||||
public removeColumns() {
|
||||
if (this._cols.length) {
|
||||
if (this.nativeViewProtected) {
|
||||
this.nativeViewProtected.clearColumns();
|
||||
}
|
||||
this._cols.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public removeRows() {
|
||||
if (this._rows.length) {
|
||||
if (this.nativeViewProtected) {
|
||||
this.nativeViewProtected.clearRows();
|
||||
}
|
||||
this._rows.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public _onRowRemoved(itemSpec: ItemSpec, index: number) {
|
||||
itemSpec.nativeSpec = null;
|
||||
if (this.nativeViewProtected) {
|
||||
this.nativeViewProtected.removeRowAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
public _onColumnRemoved(itemSpec: ItemSpec, index: number) {
|
||||
itemSpec.nativeSpec = null;
|
||||
if (this.nativeViewProtected) {
|
||||
this.nativeViewProtected.removeColumnAt(index);
|
||||
}
|
||||
|
||||
@@ -19,9 +19,13 @@ export class Page extends PageBase {
|
||||
|
||||
public createNativeView() {
|
||||
const layout = new org.nativescript.widgets.GridLayout(this._context);
|
||||
layout.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.auto));
|
||||
layout.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.star));
|
||||
|
||||
layout.addRowsFromJSON(
|
||||
JSON.stringify([
|
||||
{ value: 1, type: 0 /* org.nativescript.widgets.GridUnitType.auto */ },
|
||||
{ value: 1, type: 2 /* org.nativescript.widgets.GridUnitType.star */ },
|
||||
])
|
||||
);
|
||||
console.log('Page', 'createNativeView');
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
||||
@@ -490,18 +490,24 @@ export class TabView extends TabViewBase {
|
||||
lp.row = 1;
|
||||
|
||||
if (this.androidTabsPosition === 'top') {
|
||||
nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.auto));
|
||||
nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.star));
|
||||
|
||||
nativeView.addRowsFromJSON(
|
||||
JSON.stringify([
|
||||
{ value: 1, type: 0 /* org.nativescript.widgets.GridUnitType.auto */ },
|
||||
{ value: 1, type: 2 /* org.nativescript.widgets.GridUnitType.star */ },
|
||||
])
|
||||
);
|
||||
viewPager.setLayoutParams(lp);
|
||||
|
||||
if (!this.androidSwipeEnabled) {
|
||||
viewPager.setSwipePageEnabled(false);
|
||||
}
|
||||
} else {
|
||||
nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.star));
|
||||
nativeView.addRow(new org.nativescript.widgets.ItemSpec(1, org.nativescript.widgets.GridUnitType.auto));
|
||||
|
||||
nativeView.addRowsFromJSON(
|
||||
JSON.stringify([
|
||||
{ value: 1, type: 2 /* org.nativescript.widgets.GridUnitType.star */ },
|
||||
{ value: 1, type: 0 /* org.nativescript.widgets.GridUnitType.auto */ },
|
||||
])
|
||||
);
|
||||
tabLayout.setLayoutParams(lp);
|
||||
viewPager.setSwipePageEnabled(false);
|
||||
// set completely transparent accent color for tab selected indicator.
|
||||
|
||||
@@ -292,17 +292,24 @@
|
||||
export class GridLayout extends LayoutBase {
|
||||
constructor(context: android.content.Context);
|
||||
|
||||
public addRow(itemSpec: ItemSpec): void;
|
||||
public addColumn(itemSpec: ItemSpec): void;
|
||||
|
||||
public removeRow(itemSpec: ItemSpec): void;
|
||||
public removeColumn(itemSpec: ItemSpec): void;
|
||||
public addRow(value: number, type: org.nativescript.widgets.GridUnitType): void;
|
||||
public addColumn(value: number, type: org.nativescript.widgets.GridUnitType): void;
|
||||
|
||||
public removeRowAt(index: number): void;
|
||||
public removeColumnAt(index: number): void;
|
||||
|
||||
public getColumns(): Array<ItemSpec>;
|
||||
public getRows(): Array<ItemSpec>;
|
||||
|
||||
public clearRows();
|
||||
public clearColumns();
|
||||
public reset();
|
||||
|
||||
public addRowsFromJSON(value: string);
|
||||
public addColumnsFromJSON(value: string);
|
||||
public addRowsAndColumnsFromJSON(rows: string, columns: string);
|
||||
public getRowActualLength(index: number): number; // for testing purpose
|
||||
public getColumnActualLength(index: number): number; // for testing purpose
|
||||
}
|
||||
|
||||
export class FlexboxLayout extends LayoutBase {
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package org.nativescript.widgets;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -13,6 +18,7 @@ import java.util.HashMap;
|
||||
* @author hhristov
|
||||
*/
|
||||
public class GridLayout extends LayoutBase {
|
||||
protected final static String TAG = "GridLayout";
|
||||
|
||||
private final MeasureHelper helper = new MeasureHelper(this);
|
||||
|
||||
@@ -31,6 +37,14 @@ public class GridLayout extends LayoutBase {
|
||||
public GridLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public GridLayout(Context context, String rows) {
|
||||
this(context);
|
||||
this.addRowsFromJSON(rows);
|
||||
}
|
||||
public GridLayout(Context context, String rows, String columns) {
|
||||
this(context, rows);
|
||||
this.addColumnsFromJSON(rows);
|
||||
}
|
||||
|
||||
private static void validateItemSpec(ItemSpec itemSpec) {
|
||||
if (itemSpec == null) {
|
||||
@@ -53,6 +67,10 @@ public class GridLayout extends LayoutBase {
|
||||
this.requestLayout();
|
||||
}
|
||||
|
||||
public void addRow(int value, GridUnitType type) {
|
||||
addRow(new ItemSpec(value, type));
|
||||
}
|
||||
|
||||
public void addColumn(ItemSpec itemSpec) {
|
||||
validateItemSpec(itemSpec);
|
||||
itemSpec.owner = this;
|
||||
@@ -64,19 +82,46 @@ public class GridLayout extends LayoutBase {
|
||||
this.requestLayout();
|
||||
}
|
||||
|
||||
public void removeColumn(ItemSpec itemSpec) {
|
||||
if (itemSpec == null) {
|
||||
throw new Error("itemSpec is null.");
|
||||
}
|
||||
|
||||
int index = this._cols.indexOf(itemSpec);
|
||||
if (itemSpec.owner != this || index < 0) {
|
||||
throw new Error("itemSpec is not child of this GridLayout");
|
||||
}
|
||||
|
||||
this.removeColumnAt(index);
|
||||
public void addColumn(int value, GridUnitType type) {
|
||||
addColumn(new ItemSpec(value, type));
|
||||
}
|
||||
|
||||
public void addRowsFromJSON(String value) {
|
||||
try {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
JSONArray rows = new JSONArray(value);
|
||||
for (int i = 0; i < rows.length() ; i++) {
|
||||
JSONObject row = rows.getJSONObject(i);
|
||||
addRow(row.getInt("value"), GridUnitType.values()[row.getInt("type")]);
|
||||
}
|
||||
} catch (JSONException exception) {
|
||||
Log.e(TAG, "Caught JSONException...");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void addColumnsFromJSON(String value) {
|
||||
try {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
JSONArray columns = new JSONArray(value);
|
||||
for (int i = 0; i < columns.length() ; i++) {
|
||||
JSONObject column = columns.getJSONObject(i);
|
||||
addColumn(column.getInt("value"), GridUnitType.values()[column.getInt("type")]);
|
||||
}
|
||||
} catch (JSONException exception) {
|
||||
Log.e(TAG, "Caught JSONException...");
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void addRowsAndColumnsFromJSON(String rowsString, String jsonString) {
|
||||
addRowsFromJSON(rowsString);
|
||||
addColumnsFromJSON(jsonString);
|
||||
}
|
||||
|
||||
|
||||
public void removeColumnAt(int index) {
|
||||
this._cols.remove(index);
|
||||
this.helper.columns.get(index).children.clear();
|
||||
@@ -84,19 +129,6 @@ public class GridLayout extends LayoutBase {
|
||||
this.requestLayout();
|
||||
}
|
||||
|
||||
public void removeRow(ItemSpec itemSpec) {
|
||||
if (itemSpec == null) {
|
||||
throw new Error("itemSpec is null.");
|
||||
}
|
||||
|
||||
int index = this._rows.indexOf(itemSpec);
|
||||
if (itemSpec.owner != this || index < 0) {
|
||||
throw new Error("itemSpec is not child of this GridLayout");
|
||||
}
|
||||
|
||||
this.removeRowAt(index);
|
||||
}
|
||||
|
||||
public void removeRowAt(int index) {
|
||||
this._rows.remove(index);
|
||||
this.helper.rows.get(index).children.clear();
|
||||
@@ -116,6 +148,30 @@ public class GridLayout extends LayoutBase {
|
||||
return copy;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
clearRows();
|
||||
clearColumns();
|
||||
}
|
||||
|
||||
|
||||
public void clearRows() {
|
||||
this._rows.clear();
|
||||
for (int i = 0; i < this.helper.rows.size(); i++) {
|
||||
this.helper.rows.get(i).children.clear();
|
||||
}
|
||||
this.helper.rows.clear();
|
||||
this.requestLayout();
|
||||
}
|
||||
|
||||
public void clearColumns() {
|
||||
this._cols.clear();
|
||||
for (int i = 0; i < this.helper.columns.size(); i++) {
|
||||
this.helper.columns.get(i).children.clear();
|
||||
}
|
||||
this.helper.columns.clear();
|
||||
this.requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child) {
|
||||
super.addView(child);
|
||||
@@ -235,6 +291,16 @@ public class GridLayout extends LayoutBase {
|
||||
}
|
||||
}
|
||||
|
||||
/* only used for N tests */
|
||||
public float getRowActualLength(int index) {
|
||||
return this.helper.rows.get(index).rowOrColumn._actualLength;
|
||||
}
|
||||
|
||||
/* only used for N tests */
|
||||
public float getColumnActualLength(int index) {
|
||||
return this.helper.columns.get(index).rowOrColumn._actualLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
CommonLayoutParams.adjustChildrenLayoutParams(this, widthMeasureSpec, heightMeasureSpec);
|
||||
@@ -823,7 +889,6 @@ class MeasureHelper {
|
||||
this.measureChild(measureSpec, false);
|
||||
}
|
||||
}
|
||||
|
||||
// try fix stars!
|
||||
boolean fixColumns = canFix(this.columns);
|
||||
boolean fixRows = canFix(this.rows);
|
||||
|
||||
Reference in New Issue
Block a user