mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-08-26 11:17:04 +08:00
Disable recycling, refactoring & fixes (#4705)
* Added tests for native view recycling Disabled android native view recycling Move toString from view-common to view-base Fix crash on application restore and navigation back on API26 Added setAsRootView method Added missing logo into perf-tests/recycling app * additional fix for image-source-tests. ios is case sensitive. * Add @private to some internal properties Fix where padding is not respected when background is reset.
This commit is contained in:
BIN
apps/app/logo.png
Normal file
BIN
apps/app/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
@ -1,6 +1,8 @@
|
||||
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
|
||||
import { TextView } from "tns-core-modules/ui/text-view";
|
||||
import { Button } from "tns-core-modules/ui/button";
|
||||
import * as platform from "tns-core-modules/platform";
|
||||
import * as application from "tns-core-modules/application";
|
||||
|
||||
import * as tests from "./tests";
|
||||
|
||||
@ -13,6 +15,28 @@ function getStack(stack: StackLayout): StackLayout {
|
||||
return p;
|
||||
}
|
||||
|
||||
export function navigatingTo(args) {
|
||||
// Request permission to write test-results.xml file for API >= 23
|
||||
if (platform.isAndroid && parseInt(platform.device.sdkVersion) >= 23) {
|
||||
let handler = (args: application.AndroidActivityRequestPermissionsEventData) => {
|
||||
application.android.off(application.AndroidApplication.activityRequestPermissionsEvent, handler);
|
||||
if (args.requestCode === 1234 && args.grantResults.length > 0 && args.grantResults[0] === android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
console.log("Permission for write to external storage GRANTED!")
|
||||
} else {
|
||||
console.log("Permission for write to external storage not granted!");
|
||||
}
|
||||
};
|
||||
|
||||
application.android.on(application.AndroidApplication.activityRequestPermissionsEvent, handler);
|
||||
|
||||
if ((<any>android.support.v4.content.ContextCompat).checkSelfPermission(application.android.currentContext, (<any>android).Manifest.permission.WRITE_EXTERNAL_STORAGE) !== android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
(<any>android.support.v4.app.ActivityCompat).requestPermissions(application.android.currentContext, [(<any>android).Manifest.permission.WRITE_EXTERNAL_STORAGE], 1234);
|
||||
}
|
||||
} else {
|
||||
console.log("Permission for write to external storage GRANTED!")
|
||||
}
|
||||
}
|
||||
|
||||
export function onNavigatingFrom() {
|
||||
clearInterval(runner);
|
||||
}
|
||||
@ -39,7 +63,30 @@ export function onTap(args) {
|
||||
track(text);
|
||||
|
||||
let tasks = [
|
||||
() => track(tests.testAll(p)),
|
||||
() => track(tests.testSetup(p)),
|
||||
() => track(tests.testFlexboxLayout(p)),
|
||||
() => track(tests.testDockLayout(p)),
|
||||
() => track(tests.testGridLayout(p)),
|
||||
() => track(tests.testStackLayout(p)),
|
||||
() => track(tests.testWrapLayout(p)),
|
||||
() => track(tests.testAbsoluteLayout(p)),
|
||||
() => track(tests.testButton(p)),
|
||||
() => track(tests.testActionBar(p)),
|
||||
() => track(tests.testActivityIndicator(p)),
|
||||
() => track(tests.testBorder(p)),
|
||||
() => track(tests.testContentView(p)),
|
||||
() => track(tests.testDatePicker(p)),
|
||||
() => track(tests.testHtmlView(p)),
|
||||
() => track(tests.testImage(p)),
|
||||
() => track(tests.testLabel(p)),
|
||||
() => track(tests.testListPicker(p)),
|
||||
() => track(tests.testListView(p)),
|
||||
() => track(tests.testPage(p)),
|
||||
() => track(tests.testProgress(p)),
|
||||
() => track(tests.testRepeater(p)),
|
||||
() => track(tests.testSwitch(p)),
|
||||
() => track(tests.testTextField(p)),
|
||||
() => track(tests.testTextView(p)),
|
||||
() => track("Complete!")
|
||||
];
|
||||
let i = 0;
|
||||
|
@ -1,7 +1,9 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingFrom="onNavigatingFrom">
|
||||
<GridLayout rows="30,100,*">
|
||||
<Button text="Start test..." tap="onTap" style="font-size:8" />
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd"
|
||||
navigatingFrom="onNavigatingFrom"
|
||||
navigatingTo="navigatingTo">
|
||||
<StackLayout>
|
||||
<Button text="Start test..." tap="onTap" style="font-size:11" />
|
||||
<StackLayout id="placeholder" row="1"/>
|
||||
<TextView id="result" row="2" />
|
||||
</GridLayout>
|
||||
<TextView id="result" row="2" editable="false" />
|
||||
</StackLayout>
|
||||
</Page>
|
@ -26,42 +26,107 @@ import { TextField } from 'tns-core-modules/ui/text-field';
|
||||
import { TextView } from 'tns-core-modules/ui/text-view';
|
||||
import { TimePicker } from 'tns-core-modules/ui/time-picker';
|
||||
import { View } from 'tns-core-modules/ui/core/view';
|
||||
import { FormattedString, Span } from "tns-core-modules/text/formatted-string";
|
||||
import { FormattedString, Span } from 'tns-core-modules/text/formatted-string';
|
||||
import { _getProperties, _getStyleProperties } from 'tns-core-modules/ui/core/properties';
|
||||
declare var __startCPUProfiler;
|
||||
declare var __stopCPUProfiler;
|
||||
|
||||
export function testAll(layout: StackLayout): string {
|
||||
const count = 200;
|
||||
export function testSetup(layout: StackLayout): string {
|
||||
setupSetters();
|
||||
const count = 100;
|
||||
let result = '';
|
||||
// result += test(layout, () => new FlexboxLayout(), count);
|
||||
// result += test(layout, () => new ActionBar(), count);
|
||||
// result += test(layout, () => new ActivityIndicator(), count);
|
||||
// result += test(layout, () => new Border(), count);
|
||||
result += test(layout, () => new Button(), count);
|
||||
// result += test(layout, () => new ContentView(), count);
|
||||
// result += test(layout, () => new DatePicker(), count);
|
||||
// result += test(layout, () => new HtmlView(), count);
|
||||
// result += test(layout, () => new Image(), count);
|
||||
// result += test(layout, () => new Label(), count);
|
||||
// result += test(layout, () => new AbsoluteLayout(), count);
|
||||
// result += test(layout, () => new DockLayout(), count);
|
||||
// result += test(layout, () => new GridLayout(), count);
|
||||
// result += test(layout, () => new StackLayout(), count);
|
||||
// result += test(layout, () => new WrapLayout(), count);
|
||||
// result += test(layout, () => new ListPicker(), count);
|
||||
// result += test(layout, () => new ListView(), count);
|
||||
// result += test(layout, () => new Page(), count);
|
||||
// result += test(layout, () => new Progress(), count);
|
||||
// result += test(layout, () => new Repeater(), count);
|
||||
// result += test(layout, () => new Switch(), count);
|
||||
// result += test(layout, () => new TextField(), count);
|
||||
// result += test(layout, () => new TextView(), count);
|
||||
return '';
|
||||
}
|
||||
|
||||
// Throws
|
||||
// result += test(layout, () => new TabView(), count);
|
||||
// result += test(layout, () => new SegmentedBar(), count);
|
||||
// result += test(layout, () => new TimePicker(), count);
|
||||
export function testFlexboxLayout(layout: StackLayout): string {
|
||||
return test(layout, () => new FlexboxLayout(), count);
|
||||
}
|
||||
|
||||
return result;
|
||||
export function testDockLayout(layout: StackLayout): string {
|
||||
return test(layout, () => new DockLayout(), count);
|
||||
}
|
||||
|
||||
export function testGridLayout(layout: StackLayout): string {
|
||||
return test(layout, () => new GridLayout(), count);
|
||||
}
|
||||
|
||||
export function testStackLayout(layout: StackLayout): string {
|
||||
return test(layout, () => new StackLayout(), count);
|
||||
}
|
||||
|
||||
export function testWrapLayout(layout: StackLayout): string {
|
||||
return test(layout, () => new WrapLayout(), count);
|
||||
}
|
||||
|
||||
export function testAbsoluteLayout(layout: StackLayout): string {
|
||||
return test(layout, () => new AbsoluteLayout(), count);
|
||||
}
|
||||
|
||||
export function testButton(layout: StackLayout): string {
|
||||
return test(layout, () => new Button(), count);
|
||||
}
|
||||
|
||||
export function testActionBar(layout: StackLayout): string {
|
||||
return test(layout, () => new ActionBar(), count);
|
||||
}
|
||||
|
||||
export function testActivityIndicator(layout: StackLayout): string {
|
||||
return test(layout, () => new ActivityIndicator(), count);
|
||||
}
|
||||
|
||||
export function testBorder(layout: StackLayout): string {
|
||||
return test(layout, () => new Border(), count);
|
||||
}
|
||||
|
||||
export function testContentView(layout: StackLayout): string {
|
||||
return test(layout, () => new ContentView(), count);
|
||||
}
|
||||
|
||||
export function testDatePicker(layout: StackLayout): string {
|
||||
return test(layout, () => new DatePicker(), count);
|
||||
}
|
||||
|
||||
export function testHtmlView(layout: StackLayout): string {
|
||||
return test(layout, () => new HtmlView(), count);
|
||||
}
|
||||
|
||||
export function testImage(layout: StackLayout): string {
|
||||
return test(layout, () => new Image(), count);
|
||||
}
|
||||
|
||||
export function testLabel(layout: StackLayout): string {
|
||||
return test(layout, () => new Label(), count);
|
||||
}
|
||||
|
||||
export function testListPicker(layout: StackLayout): string {
|
||||
return test(layout, () => new ListPicker(), count);
|
||||
}
|
||||
|
||||
export function testListView(layout: StackLayout): string {
|
||||
return test(layout, () => new ListView(), count);
|
||||
}
|
||||
|
||||
export function testPage(layout: StackLayout): string {
|
||||
return test(layout, () => new Page(), count);
|
||||
}
|
||||
|
||||
export function testProgress(layout: StackLayout): string {
|
||||
return test(layout, () => new Progress(), count);
|
||||
}
|
||||
|
||||
export function testRepeater(layout: StackLayout): string {
|
||||
return test(layout, () => new Repeater(), count);
|
||||
}
|
||||
|
||||
export function testSwitch(layout: StackLayout): string {
|
||||
return test(layout, () => new Switch(), count);
|
||||
}
|
||||
|
||||
export function testTextField(layout: StackLayout): string {
|
||||
return test(layout, () => new TextField(), count);
|
||||
}
|
||||
|
||||
export function testTextView(layout: StackLayout): string {
|
||||
return test(layout, () => new TextView(), count);
|
||||
}
|
||||
|
||||
function test(layout: StackLayout, createView: () => View, count: number): string {
|
||||
@ -69,14 +134,14 @@ function test(layout: StackLayout, createView: () => View, count: number): strin
|
||||
const cssMap1 = new Map<string, any>();
|
||||
|
||||
viewMap1.set('isEnabled', false);
|
||||
let result = execute(layout, createView, count, viewMap1, cssMap1) + ', ';
|
||||
let result = execute(layout, createView, count, viewMap1, cssMap1)
|
||||
|
||||
viewMap1.set('text', 'text');
|
||||
viewMap1.set('automationText', "automationText");
|
||||
cssMap1.set('width', 100);
|
||||
cssMap1.set('height', 100);
|
||||
cssMap1.set('rotate', '90');
|
||||
result += execute(layout, createView, count, viewMap1, cssMap1) + ', ';
|
||||
result += execute(layout, createView, count, viewMap1, cssMap1)
|
||||
|
||||
viewMap1.set('clipToBounds', false);
|
||||
viewMap1.set('left', '20');
|
||||
@ -91,7 +156,7 @@ function test(layout: StackLayout, createView: () => View, count: number): strin
|
||||
cssMap1.set('horizontalAlignment', 'center');
|
||||
cssMap1.set('verticalAlignment', 'center');
|
||||
|
||||
result += execute(layout, createView, count, viewMap1, cssMap1) + ', ';
|
||||
result += execute(layout, createView, count, viewMap1, cssMap1)
|
||||
|
||||
viewMap1.set('row', '1');
|
||||
viewMap1.set('rowSpan', '2');
|
||||
@ -110,45 +175,79 @@ function test(layout: StackLayout, createView: () => View, count: number): strin
|
||||
cssMap1.set('backgroundColor', 'red');
|
||||
cssMap1.set('backgroundImage', '~/logo.png');
|
||||
|
||||
result += execute(layout, createView, count, viewMap1, cssMap1) + ', ';
|
||||
result += execute(layout, createView, count, viewMap1, cssMap1)
|
||||
result += execute(layout, createView, count, setters, cssSetters);
|
||||
|
||||
return `${createView().typeName}: ${result}\n`;
|
||||
return `${createView().typeName}: ${result}`;
|
||||
}
|
||||
|
||||
let b = false;
|
||||
function execute(layout: StackLayout, createView: () => View, count: number,
|
||||
viewProps: Map<string, any>, cssProps: Map<string, any>): string {
|
||||
const not = profile(layout, createView, count, false, viewProps, cssProps);
|
||||
const recycled = profile(layout, createView, count, true, viewProps, cssProps);
|
||||
|
||||
const improved = ((not - recycled) / not) * 100;
|
||||
console.log(`recycled time: ${recycled}`);
|
||||
console.log(`not recycled time: ${not}`);
|
||||
const propCount = viewProps.size + cssProps.size;
|
||||
return `${propCount}: ${improved.toFixed(0)}%`;
|
||||
gc();
|
||||
java.lang.System.gc();
|
||||
gc();
|
||||
java.lang.System.gc();
|
||||
// b = !b;
|
||||
// let not: { time: number, count: number };
|
||||
let recycled: { time: number, count: number };
|
||||
// if (b) {
|
||||
// not = profile(layout, createView, count, false, viewProps, cssProps);
|
||||
// recycled = profile(layout, createView, count, true, viewProps, cssProps);
|
||||
// } else {
|
||||
recycled = profile(layout, createView, count, true, viewProps, cssProps);
|
||||
// not = profile(layout, createView, count, false, viewProps, cssProps);
|
||||
// }
|
||||
|
||||
// console.log(`recycled: ${recycled.time}`);
|
||||
// console.log(`not: ${not.time}`);
|
||||
// const improved = ((not.time - recycled.time) / not.time) * 100;
|
||||
const propCount = recycled.count;
|
||||
return `\t${recycled.time.toFixed(0)}`;
|
||||
}
|
||||
|
||||
const props = _getProperties();
|
||||
const styleProps = _getStyleProperties();
|
||||
|
||||
function profile(layout: StackLayout, createView: () => View, count: number, recycle: boolean,
|
||||
viewProps: Map<string, any>, cssProps: Map<string, any>): number {
|
||||
viewProps: Map<string, any>, cssProps: Map<string, any>): { time: number, count: number } {
|
||||
|
||||
const view = createView();
|
||||
view.recycleNativeView = recycle ? 'always' : 'never';
|
||||
const style = view.style;
|
||||
// DatePicker throws OOM
|
||||
const c = view.typeName === 'DatePicker' ? 1 : 5;
|
||||
let total = 0;
|
||||
let x = 0;
|
||||
for (let i = 0; i < c; i++) {
|
||||
x = 0;
|
||||
viewProps.forEach((v, k) => {
|
||||
const p = props.find(vp => (<any>vp).name === k);
|
||||
// if (p && view[p.setNative]) {
|
||||
view[k] = v;
|
||||
x++;
|
||||
// }
|
||||
});
|
||||
|
||||
viewProps.forEach((v, k) => view[k] = v);
|
||||
cssProps.forEach((v, k) => style[k] = v);
|
||||
cssProps.forEach((v, k) => {
|
||||
const p = styleProps.find(vp => (<any>vp).name === k);
|
||||
// if (p && view[p.setNative]) {
|
||||
style[k] = v;
|
||||
x++;
|
||||
// }
|
||||
});
|
||||
|
||||
gc();
|
||||
java.lang.System.gc();
|
||||
const start = time();
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
layout.addChild(view);
|
||||
layout.removeChild(view);
|
||||
}
|
||||
|
||||
const end = time() - start;
|
||||
return end;
|
||||
total += end;
|
||||
}
|
||||
|
||||
return { time: total / c, count: x };
|
||||
}
|
||||
|
||||
let setters: Map<string, any>;
|
||||
@ -282,11 +381,11 @@ function setupSetters(): void {
|
||||
setters.set('androidOffscreenTabLimit', '2');
|
||||
|
||||
// text-base
|
||||
const formattedText = new FormattedString();
|
||||
const span = new Span();
|
||||
span.text = 'span';
|
||||
formattedText.spans.push(span);
|
||||
setters.set('formattedText', formattedText);
|
||||
// const formattedText = new FormattedString();
|
||||
// const span = new Span();
|
||||
// span.text = 'span';
|
||||
// formattedText.spans.push(span);
|
||||
// setters.set('formattedText', formattedText);
|
||||
|
||||
// text-base
|
||||
setters.set('secure', 'true');
|
||||
|
@ -6,7 +6,7 @@ export function imageSourceFromAsset(imageAsset){
|
||||
let source = new imageSource.ImageSource();
|
||||
source.fromAsset(imageAsset).then((source) => {
|
||||
let folder = fs.knownFolders.documents().path;
|
||||
let fileName = "Test.png"
|
||||
let fileName = "test.png"
|
||||
let path = fs.path.join(folder, fileName);
|
||||
let saved = source.saveToFile(path, "png");
|
||||
if(saved){
|
||||
|
@ -56,7 +56,7 @@ export function testSaveToFile() {
|
||||
// >> imagesource-save-to
|
||||
var img = imageSource.fromFile(imagePath);
|
||||
var folder = fs.knownFolders.documents();
|
||||
var path = fs.path.join(folder.path, "Test.png");
|
||||
var path = fs.path.join(folder.path, "test.png");
|
||||
var saved = img.saveToFile(path, "png");
|
||||
// << imagesource-save-to
|
||||
TKUnit.assert(saved, "Image not saved to file");
|
||||
@ -66,16 +66,16 @@ export function testSaveToFile() {
|
||||
export function testFromFile() {
|
||||
// >> imagesource-load-local
|
||||
var folder = fs.knownFolders.documents();
|
||||
var path = fs.path.join(folder.path, "Test.png");
|
||||
var path = fs.path.join(folder.path, "test.png");
|
||||
var img = imageSource.fromFile(path);
|
||||
// << imagesource-load-local
|
||||
|
||||
TKUnit.assert(img.height > 0, "image.fromResource failed");
|
||||
|
||||
// remove the image from the file system
|
||||
var file = folder.getFile("Test.png");
|
||||
var file = folder.getFile("test.png");
|
||||
file.remove();
|
||||
TKUnit.assert(!fs.File.exists(path), "Test.png not removed");
|
||||
TKUnit.assert(!fs.File.exists(path), "test.png not removed");
|
||||
}
|
||||
|
||||
export function testNativeFields() {
|
||||
|
@ -248,63 +248,65 @@ let cssSetters: Map<string, any>;
|
||||
let defaultNativeGetters: Map<string, (view) => any>;
|
||||
|
||||
export function nativeView_recycling_test(createNew: () => View, createLayout?: () => LayoutBase, nativeGetters?: Map<string, (view) => any>, customSetters?: Map<string, any>) {
|
||||
if (isIOS) {
|
||||
// recycling not implemented yet.
|
||||
return;
|
||||
}
|
||||
|
||||
setupSetters();
|
||||
const page = getClearCurrentPage();
|
||||
let layout: LayoutBase = new FlexboxLayout();
|
||||
if (createLayout) {
|
||||
// This is done on purpose. We need the constructor of Flexbox
|
||||
// to run otherwise some module fileds stays uninitialized.
|
||||
layout = createLayout();
|
||||
}
|
||||
// if (isIOS) {
|
||||
// // recycling not implemented yet.
|
||||
// return;
|
||||
// }
|
||||
|
||||
page.content = layout;
|
||||
// setupSetters();
|
||||
// const page = getClearCurrentPage();
|
||||
// let layout: LayoutBase = new FlexboxLayout();
|
||||
// if (createLayout) {
|
||||
// // This is done on purpose. We need the constructor of Flexbox
|
||||
// // to run otherwise some module fileds stays uninitialized.
|
||||
// layout = createLayout();
|
||||
// }
|
||||
|
||||
const first = createNew();
|
||||
const test = createNew();
|
||||
// page.content = layout;
|
||||
|
||||
// Make sure we are not reusing a native views.
|
||||
first.recycleNativeView = "never";
|
||||
test.recycleNativeView = "never";
|
||||
// const first = createNew();
|
||||
// const test = createNew();
|
||||
|
||||
page.content = layout;
|
||||
// // Make sure we are not reusing a native views.
|
||||
// first.recycleNativeView = "never";
|
||||
// test.recycleNativeView = "never";
|
||||
|
||||
layout.addChild(test);
|
||||
// page.content = layout;
|
||||
|
||||
setValue(test.style, cssSetters);
|
||||
setValue(test, setters, customSetters);
|
||||
// Needed so we can reset formattedText
|
||||
test["secure"] = false;
|
||||
// layout.addChild(test);
|
||||
|
||||
const nativeView = test.nativeViewProtected;
|
||||
// Mark so we reuse the native views.
|
||||
test.recycleNativeView = "always";
|
||||
layout.removeChild(test);
|
||||
const newer = createNew();
|
||||
newer.recycleNativeView = "always";
|
||||
layout.addChild(newer);
|
||||
layout.addChild(first);
|
||||
// setValue(test.style, cssSetters);
|
||||
// setValue(test, setters, customSetters);
|
||||
// // Needed so we can reset formattedText
|
||||
// test["secure"] = false;
|
||||
|
||||
if (first.typeName !== "SearchBar") {
|
||||
// There are way too many differences in native methods for search-bar.
|
||||
// There are too many methods that just throw for newly created views in API lvl 19 and 17
|
||||
if (sdkVersion < 21) {
|
||||
TKUnit.waitUntilReady(() => layout.isLayoutValid);
|
||||
}
|
||||
// const nativeView = test.nativeViewProtected;
|
||||
// // Mark so we reuse the native views.
|
||||
// test.recycleNativeView = "always";
|
||||
// layout.removeChild(test);
|
||||
// const newer = createNew();
|
||||
// newer.recycleNativeView = "always";
|
||||
// layout.addChild(newer);
|
||||
// layout.addChild(first);
|
||||
|
||||
compareUsingReflection(newer, first);
|
||||
}
|
||||
// if (first.typeName !== "SearchBar") {
|
||||
// // There are way too many differences in native methods for search-bar.
|
||||
// // There are too many methods that just throw for newly created views in API lvl 19 and 17
|
||||
// if (sdkVersion < 21) {
|
||||
// TKUnit.waitUntilReady(() => layout.isLayoutValid);
|
||||
// }
|
||||
|
||||
TKUnit.assertEqual(newer.nativeViewProtected, nativeView, "nativeView not reused.");
|
||||
checkDefaults(newer, first, props, nativeGetters || defaultNativeGetters);
|
||||
checkDefaults(newer, first, styleProps, nativeGetters || defaultNativeGetters);
|
||||
// compareUsingReflection(newer, first);
|
||||
// }
|
||||
|
||||
layout.removeChild(newer);
|
||||
layout.removeChild(first);
|
||||
// TKUnit.assertEqual(newer.nativeViewProtected, nativeView, "nativeView not reused.");
|
||||
// checkDefaults(newer, first, props, nativeGetters || defaultNativeGetters);
|
||||
// checkDefaults(newer, first, styleProps, nativeGetters || defaultNativeGetters);
|
||||
|
||||
// layout.removeChild(newer);
|
||||
// layout.removeChild(first);
|
||||
}
|
||||
|
||||
function compareUsingReflection(recycledNativeView: View, newNativeView: View): void {
|
||||
|
@ -601,8 +601,12 @@ export function test_NativeSetter_called_when_add_and_remove_and_recycled() {
|
||||
firstView.removeChild(secondView);
|
||||
|
||||
// we don't recycle nativeViews on iOS yet so reset is not called.
|
||||
TKUnit.assertEqual(secondView.cssPropCounter, isIOS ? 2 : 3, "7");
|
||||
TKUnit.assertEqual(secondView.viewPropCounter, isIOS ? 2 : 3, "8");
|
||||
// Recycling disabled for android too
|
||||
// TKUnit.assertEqual(secondView.cssPropCounter, isIOS ? 2 : 3, "7");
|
||||
// TKUnit.assertEqual(secondView.viewPropCounter, isIOS ? 2 : 3, "8");
|
||||
|
||||
TKUnit.assertEqual(secondView.cssPropCounter, 2, "7");
|
||||
TKUnit.assertEqual(secondView.viewPropCounter,2, "8");
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
import * as commonTests from "./view-tests-common";
|
||||
import * as helper from "../../ui/helper";
|
||||
import * as view from "tns-core-modules/ui/core/view";
|
||||
import * as button from "tns-core-modules/ui/button";
|
||||
import { Button } from "tns-core-modules/ui/button";
|
||||
import * as types from "tns-core-modules/utils/types";
|
||||
import * as stack from "tns-core-modules/ui/layouts/stack-layout";
|
||||
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
|
||||
import * as labelModule from "tns-core-modules/ui/label";
|
||||
import * as frame from "tns-core-modules/ui/frame";
|
||||
import * as trace from "tns-core-modules/trace";
|
||||
@ -14,6 +14,101 @@ trace.enable();
|
||||
|
||||
global.moduleMerge(commonTests, exports);
|
||||
|
||||
// function setup(): StackLayout {
|
||||
// const page = helper.getClearCurrentPage();
|
||||
// const stack = new StackLayout();
|
||||
// page.content = stack;
|
||||
// return stack;
|
||||
// }
|
||||
|
||||
// export function test_recycle_native_view_never() {
|
||||
// const stack = setup();
|
||||
// const btn = new Button();
|
||||
// btn.recycleNativeView = 'never';
|
||||
// stack.addChild(btn);
|
||||
// TKUnit.assertNotNull(btn.nativeViewProtected);
|
||||
|
||||
// const oldNativeView = btn.nativeViewProtected;
|
||||
// stack.removeChild(btn);
|
||||
// stack.addChild(btn);
|
||||
// const newNativeView = btn.nativeViewProtected;
|
||||
// TKUnit.assertNotEqual(oldNativeView, newNativeView);
|
||||
// }
|
||||
|
||||
// export function test_recycle_native_view_always() {
|
||||
// const stack = setup();
|
||||
// const btn = new Button();
|
||||
// btn.recycleNativeView = 'always';
|
||||
// stack.addChild(btn);
|
||||
// TKUnit.assertNotNull(btn.nativeViewProtected);
|
||||
|
||||
// const oldNativeView = btn.nativeViewProtected;
|
||||
// stack.removeChild(btn);
|
||||
// stack.addChild(btn);
|
||||
// const newNativeView = btn.nativeViewProtected;
|
||||
// TKUnit.assertEqual(oldNativeView, newNativeView);
|
||||
// }
|
||||
|
||||
// export function test_recycle_native_view_auto_access_nativeView() {
|
||||
// const stack = setup();
|
||||
// const btn = new Button();
|
||||
// btn.recycleNativeView = 'auto';
|
||||
// stack.addChild(btn);
|
||||
// TKUnit.assertNotNull(btn.nativeView);
|
||||
|
||||
// const oldNativeView = btn.nativeViewProtected;
|
||||
// stack.removeChild(btn);
|
||||
// stack.addChild(btn);
|
||||
// const newNativeView = btn.nativeViewProtected;
|
||||
// TKUnit.assertNotEqual(oldNativeView, newNativeView);
|
||||
// }
|
||||
|
||||
// export function test_recycle_native_view_auto_access_android() {
|
||||
// const stack = setup();
|
||||
// const btn = new Button();
|
||||
// btn.recycleNativeView = 'auto';
|
||||
// stack.addChild(btn);
|
||||
// TKUnit.assertNotNull(btn.android);
|
||||
|
||||
// const oldNativeView = btn.nativeViewProtected;
|
||||
// stack.removeChild(btn);
|
||||
// stack.addChild(btn);
|
||||
// const newNativeView = btn.nativeViewProtected;
|
||||
// TKUnit.assertNotEqual(oldNativeView, newNativeView);
|
||||
// }
|
||||
|
||||
// export function test_recycle_property_counter_few_properties() {
|
||||
// const stack = setup();
|
||||
// const btn = new Button();
|
||||
// btn.text = "text";
|
||||
// btn.recycleNativeView = 'auto';
|
||||
// stack.addChild(btn);
|
||||
// TKUnit.assertNotNull(btn.nativeViewProtected);
|
||||
|
||||
// const oldNativeView = btn.nativeViewProtected;
|
||||
// stack.removeChild(btn);
|
||||
// stack.addChild(btn);
|
||||
// const newNativeView = btn.nativeViewProtected;
|
||||
// TKUnit.assertEqual(oldNativeView, newNativeView);
|
||||
// }
|
||||
|
||||
// export function test_recycle_property_counter_more_properties() {
|
||||
// const stack = setup();
|
||||
// const btn = new Button();
|
||||
// btn.recyclePropertyCounter = 1;
|
||||
// btn.recycleNativeView = 'auto';
|
||||
// btn.text = "text";
|
||||
// btn.style.margin = "20";
|
||||
// stack.addChild(btn);
|
||||
// TKUnit.assertNotNull(btn.nativeViewProtected);
|
||||
|
||||
// const oldNativeView = btn.nativeViewProtected;
|
||||
// stack.removeChild(btn);
|
||||
// stack.addChild(btn);
|
||||
// const newNativeView = btn.nativeViewProtected;
|
||||
// TKUnit.assertNotEqual(oldNativeView, newNativeView);
|
||||
// }
|
||||
|
||||
export const test_event_setupUI_IsRaised = function () {
|
||||
const listener = new Listener("_setupUI");
|
||||
trace.addEventListener(listener);
|
||||
@ -38,8 +133,8 @@ export const test_event_setupUI_IsRaised_WhenAttached_Dynamically = function ()
|
||||
const listener = new Listener("_setupUI");
|
||||
trace.addEventListener(listener);
|
||||
|
||||
const newButton = new button.Button();
|
||||
(<stack.StackLayout>views[1]).addChild(newButton);
|
||||
const newButton = new Button();
|
||||
(<StackLayout>views[1]).addChild(newButton);
|
||||
|
||||
TKUnit.assertEqual(listener.receivedEvents.length, 1);
|
||||
TKUnit.assertEqual(listener.receivedEvents[0].name, "_setupUI");
|
||||
@ -75,8 +170,8 @@ export const test_event_onContextChanged_IsRaised_WhenAttached_Dynamically = fun
|
||||
const listener = new Listener("_onContextChanged");
|
||||
trace.addEventListener(listener);
|
||||
|
||||
const newButton = new button.Button();
|
||||
(<stack.StackLayout>views[1]).addChild(newButton);
|
||||
const newButton = new Button();
|
||||
(<StackLayout>views[1]).addChild(newButton);
|
||||
|
||||
TKUnit.assertEqual(listener.receivedEvents.length, 1);
|
||||
TKUnit.assertEqual(listener.receivedEvents[0].name, "_onContextChanged");
|
||||
@ -125,7 +220,7 @@ export const test_event_tearDownUI_IsRaised_WhenRemoved_Dynamically = function (
|
||||
trace.addEventListener(listener);
|
||||
|
||||
// remove the button from the layout
|
||||
(<stack.StackLayout>views[1]).removeChild(views[2]);
|
||||
(<StackLayout>views[1]).removeChild(views[2]);
|
||||
|
||||
TKUnit.assertEqual(listener.receivedEvents.length, 1);
|
||||
TKUnit.assertEqual(listener.receivedEvents[0].name, "_tearDownUI");
|
||||
@ -142,8 +237,8 @@ export const test_events_tearDownUIAndRemovedFromNativeVisualTree_AreRaised_When
|
||||
let removeFromNativeVisualTreeListener = new Listener("_removeViewFromNativeVisualTree");
|
||||
|
||||
let page = frame.topmost().currentPage;
|
||||
let stackLayout = new stack.StackLayout();
|
||||
let btn = new button.Button();
|
||||
let stackLayout = new StackLayout();
|
||||
let btn = new Button();
|
||||
stackLayout.addChild(btn);
|
||||
page.content = stackLayout;
|
||||
|
||||
@ -174,11 +269,11 @@ export const test_events_tearDownUIAndRemovedFromNativeVisualTree_AreRaised_When
|
||||
|
||||
export const test_cachedProperties_Applied_WhenNativeWidged_IsCreated = function () {
|
||||
const test = function (views: Array<view.View>) {
|
||||
const newButton = new button.Button();
|
||||
const newButton = new Button();
|
||||
newButton.text = "Test Button";
|
||||
TKUnit.assert(types.isUndefined(newButton.android));
|
||||
|
||||
(<stack.StackLayout>views[1]).addChild(newButton);
|
||||
(<StackLayout>views[1]).addChild(newButton);
|
||||
|
||||
TKUnit.assert(types.isDefined(newButton.android));
|
||||
// TODO: There is currently an issue with the getText conversion to JavaScript string
|
||||
@ -190,9 +285,9 @@ export const test_cachedProperties_Applied_WhenNativeWidged_IsCreated = function
|
||||
|
||||
export function test_automation_text_set_to_native() {
|
||||
const test = function (views: Array<view.View>) {
|
||||
const newButton = new button.Button();
|
||||
const newButton = new Button();
|
||||
newButton.automationText = "Button1";
|
||||
(<stack.StackLayout>views[1]).addChild(newButton);
|
||||
(<StackLayout>views[1]).addChild(newButton);
|
||||
TKUnit.assertEqual((<android.widget.Button>newButton.android).getContentDescription(), "Button1", "contentDescription not set to native view.");
|
||||
};
|
||||
|
||||
@ -234,9 +329,9 @@ class Listener implements trace.EventListener {
|
||||
export const test_StylePropertiesDefaultValuesCache = function () {
|
||||
const testValue = 35;
|
||||
|
||||
const test = function (views: [view.View, stack.StackLayout, button.Button, view.View]) {
|
||||
const test = function (views: [view.View, StackLayout, Button, view.View]) {
|
||||
const testLabel = new labelModule.Label();
|
||||
const testButton = new button.Button();
|
||||
const testButton = new Button();
|
||||
|
||||
const stack = views[1];
|
||||
|
||||
|
@ -215,6 +215,7 @@ function createRootView(v?: View) {
|
||||
rootView = frame;
|
||||
}
|
||||
|
||||
rootView._setupAsRootView({});
|
||||
return rootView;
|
||||
}
|
||||
|
||||
|
@ -144,8 +144,6 @@ export abstract class ViewBase extends Observable {
|
||||
* read-only. If you want to set out-of-band the nativeView use the setNativeView method.
|
||||
*/
|
||||
public nativeViewProtected: any;
|
||||
public recycleNativeView: "always" | "never" | "auto";
|
||||
|
||||
public nativeView: any;
|
||||
public bindingContext: any;
|
||||
|
||||
@ -306,6 +304,14 @@ export abstract class ViewBase extends Observable {
|
||||
public ensureDomNode();
|
||||
|
||||
//@private
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public recycleNativeView: "always" | "never" | "auto";
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
public _isPaddingRelative: boolean;
|
||||
public _styleScope: any;
|
||||
|
||||
/**
|
||||
@ -321,6 +327,10 @@ export abstract class ViewBase extends Observable {
|
||||
* Allow multiple updates to be performed on the instance at once.
|
||||
*/
|
||||
public _batchUpdate<T>(callback: () => T): T;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_setupAsRootView(context: any): void;
|
||||
//@endprivate
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf } from "../../la
|
||||
import { KeyframeAnimation } from "../../animation/keyframe-animation";
|
||||
|
||||
// Types.
|
||||
import { Source } from "../../../utils/debug";
|
||||
import { Property, CssProperty, CssAnimationProperty, InheritedProperty, Style, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, resetCSSProperties, initNativeView, resetNativeView } from "../properties";
|
||||
import { Binding, BindingOptions, Observable, WrappedValue, PropertyChangeData, traceEnabled, traceWrite, traceCategories, traceNotifyEvent } from "../bindable";
|
||||
import { isIOS, isAndroid } from "../../../platform";
|
||||
@ -94,40 +95,40 @@ export function eachDescendant(view: ViewBaseDefinition, callback: (child: ViewB
|
||||
|
||||
let viewIdCounter = 1;
|
||||
|
||||
const contextMap = new WeakMap<Object, Map<string, WeakRef<Object>[]>>();
|
||||
// const contextMap = new WeakMap<Object, Map<string, WeakRef<Object>[]>>();
|
||||
|
||||
function getNativeView(context: Object, typeName: string): Object {
|
||||
let typeMap = contextMap.get(context);
|
||||
if (!typeMap) {
|
||||
typeMap = new Map<string, WeakRef<Object>[]>();
|
||||
contextMap.set(context, typeMap);
|
||||
return undefined;
|
||||
}
|
||||
// function getNativeView(context: Object, typeName: string): Object {
|
||||
// let typeMap = contextMap.get(context);
|
||||
// if (!typeMap) {
|
||||
// typeMap = new Map<string, WeakRef<Object>[]>();
|
||||
// contextMap.set(context, typeMap);
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
const array = typeMap.get(typeName);
|
||||
if (array) {
|
||||
let nativeView;
|
||||
while (array.length > 0) {
|
||||
const weakRef = array.pop();
|
||||
nativeView = weakRef.get();
|
||||
if (nativeView) {
|
||||
return nativeView;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
// const array = typeMap.get(typeName);
|
||||
// if (array) {
|
||||
// let nativeView;
|
||||
// while (array.length > 0) {
|
||||
// const weakRef = array.pop();
|
||||
// nativeView = weakRef.get();
|
||||
// if (nativeView) {
|
||||
// return nativeView;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
function putNativeView(context: Object, view: ViewBase): void {
|
||||
const typeMap = contextMap.get(context);
|
||||
const typeName = view.typeName;
|
||||
let list = typeMap.get(typeName);
|
||||
if (!list) {
|
||||
list = [];
|
||||
typeMap.set(typeName, list);
|
||||
}
|
||||
list.push(new WeakRef(view.nativeViewProtected));
|
||||
}
|
||||
// function putNativeView(context: Object, view: ViewBase): void {
|
||||
// const typeMap = contextMap.get(context);
|
||||
// const typeName = view.typeName;
|
||||
// let list = typeMap.get(typeName);
|
||||
// if (!list) {
|
||||
// list = [];
|
||||
// typeMap.set(typeName, list);
|
||||
// }
|
||||
// list.push(new WeakRef(view.nativeViewProtected));
|
||||
// }
|
||||
|
||||
export abstract class ViewBase extends Observable implements ViewBaseDefinition {
|
||||
public static loadedEvent = "loaded";
|
||||
@ -141,7 +142,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
private _visualState: string;
|
||||
private _inlineStyleSelector: SelectorCore;
|
||||
private __nativeView: any;
|
||||
private _disableNativeViewRecycling: boolean;
|
||||
// private _disableNativeViewRecycling: boolean;
|
||||
public domNode: DOMNode;
|
||||
|
||||
public recycleNativeView: "always" | "never" | "auto";
|
||||
@ -204,7 +205,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
public _defaultPaddingRight: number;
|
||||
public _defaultPaddingBottom: number;
|
||||
public _defaultPaddingLeft: number;
|
||||
private _isPaddingRelative: boolean;
|
||||
public _isPaddingRelative: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@ -213,7 +214,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
|
||||
get nativeView(): any {
|
||||
this._disableNativeViewRecycling = true;
|
||||
// this._disableNativeViewRecycling = true;
|
||||
return this.nativeViewProtected;
|
||||
}
|
||||
|
||||
@ -230,7 +231,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
|
||||
get android(): any {
|
||||
this._disableNativeViewRecycling = true;
|
||||
// this._disableNativeViewRecycling = true;
|
||||
return this._androidView;
|
||||
}
|
||||
|
||||
@ -670,25 +671,29 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
|
||||
private resetNativeViewInternal(): void {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (nativeView && isAndroid) {
|
||||
const recycle = this.recycleNativeView;
|
||||
if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
resetNativeView(this);
|
||||
if (this._isPaddingRelative) {
|
||||
nativeView.setPaddingRelative(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
} else {
|
||||
nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
}
|
||||
this.resetNativeView();
|
||||
}
|
||||
}
|
||||
// const nativeView = this.nativeViewProtected;
|
||||
// if (nativeView && isAndroid) {
|
||||
// const recycle = this.recycleNativeView;
|
||||
// if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
// resetNativeView(this);
|
||||
// if (this._isPaddingRelative) {
|
||||
// nativeView.setPaddingRelative(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
// } else {
|
||||
// nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
// }
|
||||
// this.resetNativeView();
|
||||
// }
|
||||
// }
|
||||
|
||||
if (this._cssState) {
|
||||
this._cancelAllAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
_setupAsRootView(context: any): void {
|
||||
this._setupUI(context);
|
||||
}
|
||||
|
||||
@profile
|
||||
public _setupUI(context: android.content.Context, atIndex?: number, parentIsLoaded?: boolean) {
|
||||
|
||||
@ -706,10 +711,10 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
let nativeView;
|
||||
if (isAndroid) {
|
||||
const recycle = this.recycleNativeView;
|
||||
if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
nativeView = <android.view.View>getNativeView(context, this.typeName);
|
||||
}
|
||||
// const recycle = this.recycleNativeView;
|
||||
// if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
// nativeView = <android.view.View>getNativeView(context, this.typeName);
|
||||
// }
|
||||
|
||||
if (!nativeView) {
|
||||
nativeView = <android.view.View>this.createNativeView();
|
||||
@ -790,15 +795,15 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
@profile
|
||||
public _tearDownUI(force?: boolean) {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${this}._tearDownUI(${force})`, traceCategories.VisualTreeEvents);
|
||||
}
|
||||
|
||||
// No context means we are already teared down.
|
||||
if (!this._context) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${this}._tearDownUI(${force})`, traceCategories.VisualTreeEvents);
|
||||
}
|
||||
|
||||
this.resetNativeViewInternal();
|
||||
|
||||
this.eachChild((child) => {
|
||||
@ -810,18 +815,24 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
this.parent._removeViewFromNativeVisualTree(this);
|
||||
}
|
||||
|
||||
const nativeView = this.nativeViewProtected;
|
||||
if (nativeView && isAndroid) {
|
||||
const recycle = this.recycleNativeView;
|
||||
if (recycle === "always" || (recycle === "auto" && !this._disableNativeViewRecycling)) {
|
||||
// const nativeParent = isAndroid ? (<android.view.View>nativeView).getParent() : (<UIView>nativeView).superview;
|
||||
const nativeParent = (<android.view.View>nativeView).getParent();
|
||||
const animation = (<android.view.View>nativeView).getAnimation();
|
||||
if (!nativeParent && !animation) {
|
||||
putNativeView(this._context, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
// const nativeView = this.nativeViewProtected;
|
||||
// if (nativeView && isAndroid) {
|
||||
// const recycle = this.recycleNativeView;
|
||||
// let shouldRecycle = false;
|
||||
// if (recycle === "always") {
|
||||
// shouldRecycle = true;
|
||||
// } else if (recycle === "auto" && !this._disableNativeViewRecycling) {
|
||||
// const propertiesSet = Object.getOwnPropertySymbols(this).length + Object.getOwnPropertySymbols(this.style).length / 2;
|
||||
// shouldRecycle = propertiesSet <= this.recyclePropertyCounter;
|
||||
// }
|
||||
|
||||
// // const nativeParent = isAndroid ? (<android.view.View>nativeView).getParent() : (<UIView>nativeView).superview;
|
||||
// const nativeParent = (<android.view.View>nativeView).getParent();
|
||||
// const animation = (<android.view.View>nativeView).getAnimation();
|
||||
// if (shouldRecycle && !nativeParent && !animation) {
|
||||
// putNativeView(this._context, this);
|
||||
// }
|
||||
// }
|
||||
|
||||
this.disposeNativeView();
|
||||
|
||||
@ -941,6 +952,21 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
let str = this.typeName;
|
||||
if (this.id) {
|
||||
str += `<${this.id}>`;
|
||||
} else {
|
||||
str += `(${this._domId})`;
|
||||
}
|
||||
let source = Source.get(this);
|
||||
if (source) {
|
||||
str += `@${source};`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
ViewBase.prototype.isCollapsed = false;
|
||||
|
@ -2,9 +2,6 @@
|
||||
import { View as ViewDefinition, Point, Size, Color, dip } from ".";
|
||||
import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties";
|
||||
|
||||
// Types.
|
||||
import { Source } from "../../../utils/debug";
|
||||
|
||||
import {
|
||||
ViewBase, Property, booleanConverter, EventData, layout,
|
||||
getEventOrGestureName, traceEnabled, traceWrite, traceCategories
|
||||
@ -747,21 +744,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
super.resetNativeView();
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
let str = this.typeName;
|
||||
if (this.id) {
|
||||
str += `<${this.id}>`;
|
||||
} else {
|
||||
str += `(${this._domId})`;
|
||||
}
|
||||
let source = Source.get(this);
|
||||
if (source) {
|
||||
str += `@${source};`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public _setNativeViewFrame(nativeView: any, frame: any) {
|
||||
//
|
||||
}
|
||||
|
@ -7,7 +7,8 @@ import { CacheLayerType } from "../../../utils/utils";
|
||||
import { Background, ad as androidBackground } from "../../styling/background";
|
||||
import {
|
||||
ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty,
|
||||
traceEnabled, traceWrite, traceCategories, traceNotifyEvent
|
||||
traceEnabled, traceWrite, traceCategories, traceNotifyEvent,
|
||||
paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty
|
||||
} from "./view-common";
|
||||
|
||||
import {
|
||||
@ -486,7 +487,18 @@ export class View extends ViewCommon {
|
||||
} else {
|
||||
const nativeView = this.nativeViewProtected;
|
||||
org.nativescript.widgets.ViewHelper.setBackground(nativeView, value);
|
||||
nativeView.setPadding(this._defaultPaddingLeft, this._defaultPaddingTop, this._defaultPaddingRight, this._defaultPaddingBottom);
|
||||
|
||||
const style = this.style;
|
||||
const paddingTop = paddingTopProperty.isSet(style) ? this.effectivePaddingTop : this._defaultPaddingTop;
|
||||
const paddingRight = paddingRightProperty.isSet(style) ? this.effectivePaddingRight : this._defaultPaddingRight;
|
||||
const paddingBottom = paddingBottomProperty.isSet(style) ? this.effectivePaddingBottom : this._defaultPaddingBottom;
|
||||
const paddingLeft = paddingLeftProperty.isSet(style) ? this.effectivePaddingLeft : this._defaultPaddingLeft;
|
||||
|
||||
if (this._isPaddingRelative) {
|
||||
nativeView.setPaddingRelative(paddingLeft, paddingTop, paddingRight, paddingBottom);
|
||||
} else {
|
||||
nativeView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
|
||||
}
|
||||
|
||||
(<any>nativeView).background = undefined;
|
||||
const cache = <CacheLayerType><any>nativeView;
|
||||
|
@ -334,6 +334,22 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
this._updateActionBar();
|
||||
}
|
||||
|
||||
public _findEntryForTag(fragmentTag: string): BackstackEntry {
|
||||
let entry: BackstackEntry;
|
||||
if (this._currentEntry && this._currentEntry.fragmentTag === fragmentTag) {
|
||||
entry = this._currentEntry;
|
||||
} else {
|
||||
entry = this._backStack.find((value) => value.fragmentTag === fragmentTag);
|
||||
// on API 26 fragments are recreated lazily after activity is destroyed.
|
||||
if (!entry) {
|
||||
const navigationItem = this._navigationQueue.find((value) => value.entry.fragmentTag === fragmentTag);
|
||||
entry = navigationItem ? navigationItem.entry : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
public navigationQueueIsEmpty(): boolean {
|
||||
return this._navigationQueue.length === 0;
|
||||
}
|
||||
|
@ -419,13 +419,7 @@ function findPageForFragment(fragment: android.app.Fragment, frame: Frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
let entry: BackstackEntry;
|
||||
if (frame._currentEntry && frame._currentEntry.fragmentTag === fragmentTag) {
|
||||
entry = frame._currentEntry;
|
||||
} else {
|
||||
entry = frame.backStack.find((value) => value.fragmentTag === fragmentTag);
|
||||
}
|
||||
|
||||
const entry = frame._findEntryForTag(fragmentTag);
|
||||
const page = entry ? entry.resolvedPage : undefined;
|
||||
if (page) {
|
||||
const callbacks: FragmentCallbacksImplementation = fragment[CALLBACKS];
|
||||
@ -668,7 +662,7 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks {
|
||||
this._rootView = rootView;
|
||||
|
||||
// Initialize native visual tree;
|
||||
rootView._setupUI(activity);
|
||||
rootView._setupAsRootView(activity);
|
||||
activity.setContentView(rootView.nativeViewProtected, new org.nativescript.widgets.CommonLayoutParams());
|
||||
// frameId is negative w
|
||||
if (frame) {
|
||||
|
4
tns-core-modules/ui/frame/frame.d.ts
vendored
4
tns-core-modules/ui/frame/frame.d.ts
vendored
@ -132,6 +132,10 @@ export class Frame extends View {
|
||||
* @private
|
||||
*/
|
||||
_getNavBarVisible(page: Page): boolean;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_findEntryForTag(fragmentTag: string): BackstackEntry;
|
||||
//@endprivate
|
||||
|
||||
/**
|
||||
|
@ -20,8 +20,6 @@ const DELEGATE = "_delegate";
|
||||
|
||||
let navDepth = -1;
|
||||
|
||||
const FRAME_CONTEXT = {};
|
||||
|
||||
export class Frame extends FrameBase {
|
||||
private _ios: iOSFrame;
|
||||
private _paramToNavigate: any;
|
||||
@ -35,13 +33,6 @@ export class Frame extends FrameBase {
|
||||
public _bottom: number;
|
||||
public _isInitialNavigation: boolean = true;
|
||||
|
||||
public get _context(): any {
|
||||
return FRAME_CONTEXT;
|
||||
}
|
||||
public set _context(value: any) {
|
||||
throw new Error("Frame _context is readonly");
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._ios = new iOSFrame(this);
|
||||
@ -255,10 +246,6 @@ export class Frame extends FrameBase {
|
||||
return this._ios;
|
||||
}
|
||||
|
||||
// get nativeView(): any {
|
||||
// return this._ios.controller.view;
|
||||
// }
|
||||
|
||||
public static get defaultAnimatedNavigation(): boolean {
|
||||
return FrameBase.defaultAnimatedNavigation;
|
||||
}
|
||||
@ -495,10 +482,10 @@ class UINavigationControllerImpl extends UINavigationController {
|
||||
}
|
||||
|
||||
@profile
|
||||
public viewDidLoad(): void {
|
||||
super.viewDidLoad();
|
||||
public viewWillAppear(animated: boolean): void {
|
||||
super.viewWillAppear(animated);
|
||||
let owner = this._owner.get();
|
||||
if (owner) {
|
||||
if (owner && (!owner.isLoaded && !owner.parent)) {
|
||||
owner.onLoaded();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user