8000 feat: reusable views by edusperoni · Pull Request #9163 · NativeScript/NativeScript · GitHub
[go: up one dir, main page]

Skip to content

feat: reusable views #9163

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions apps/ui/src/issues/issue-7469-page.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.test-label {
padding: 10;
background-color: black;
color: white;
}

.stack1 {
background-color: green;
color: white;
}

.stack2 {
background-color: blue;
color: red;
}
158 changes: 158 additions & 0 deletions apps/ui/src/issues/issue-7469-page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { EventData, Label, StackLayout } from '@nativescript/core';
import { addCallback, removeCallback, start, stop } from '@nativescript/core/fps-meter';

let callbackId;
let fpsLabel: any;
export function startFPSMeter() {
callbackId = addCallback((fps: number, minFps: number) => {
// console.log(`Frames per seconds: ${fps.toFixed(2)}`);
// console.log(minFps.toFixed(2));
if (fpsLabel) {
fpsLabel.text = `${fps}`;
}
});
start();
}

export function stopFPSMeter() {
removeCallback(callbackId);
stop();
}

let timeouts = [];
let intervals = [];

let reusableItem;
let vcToggle;
let loaded = false;
let isIn1 = false;

function updateVcToggleText() {
vcToggle.text = `Container is${reusableItem.reusable ? ' ' : ' NOT '}Reusable`
}

export function pageLoaded(args) {
startFPSMeter();
if (loaded) {
fpsLabel = null;
// stopFPSMeter();
timeouts.forEach((v) => clearTimeout(v));
intervals.forEach((v) => clearInterval(v));
reusableItem._tearDownUI(true);
}
loaded = true;
reusableItem = args.object.getViewById('reusableItem');
vcToggle = args.object.getViewById('vcToggle');
updateVcToggleText();
fpsLabel = args.object.getViewById('fpslabel');
const stack1: StackLayout = args.object.getViewById('stack1');
const stack2: StackLayout = args.object.getViewById('stack2');
setTimeout(() => {
// label.android.setTextColor(new Color("red").android);
// label.android.setBackgroundColor(new Color("red").android);
startFPSMeter();
console.log('setRed');
}, 1000);
// console.log(label._context);
// isIn1 = false;
// timeouts.push(setTimeout(() => {
// intervals.push(setInterval(() => {
// label.parent.removeChild(label);
// // console.log(label.nativeView);
// if(isIn1) {
// isIn1 = false;
// stack2.addChild(label);
// } else {
// isIn1 = true;
// stack1.addChild(label);
// }
// }, 10));
// }, 1001));
}

export function pageUnloaded(args) {
//
}

export function makeReusable(args: EventData) {
console.log('loaded:', args.object);
// console.log("making reusable");
if ((args.object as any).___reusableRan) {
return;
}
(args.object as any).___reusableRan = true;
(args.object as any).reusable = true;
if(args.object === reusableItem) {
updateVcToggleText();
}
}

export function onReusableUnloaded(args: EventData) {
console.log('unloaded:', args.object);
}
var testLabel: Label;

export function test(args: any) {
const page = args.object.page;
reusableItem = page.getViewById('reusableItem');
const stack1: StackLayout = page.getViewById('stack1');
const stack2: StackLayout = page.getViewById('stack2');
if (!testLabel) {
testLabel = new Label();
testLabel.text = 'This label is not reusable and is dynamic';
testLabel.on('loaded', () => {
console.log('LODADED testLabel');
});
testLabel.on('unloaded', () => {
console.log('UNLODADED testLabel');
});
}
reusableItem.parent.removeChild(reusableItem);
if (!reusableItem._suspendNativeUpdatesCount) {
console.log('reusableItem SHOULD BE UNLOADED');
}
if (!testLabel._suspendNativeUpdatesCount) {
console.log('testLabel SHOULD BE UNLOADED');
}
if (!testLabel.parent) {
reusableItem.addChild(testLabel);
}
if (!testLabel.nativeView) {
console.log('testLabel NATIVE VIEW SHOULD BE CREATED');
}
if (!testLabel._suspendNativeUpdatesCount) {
console.log('testLabel SHOULD BE UNLOADED');
}
if (isIn1) {
isIn1 = false;
stack2.addChild(reusableItem);
} else {
isIn1 = true;
stack1.addChild(reusableItem);
}
if (reusableItem._suspendNativeUpdatesCount) {
console.log('reusableItem SHOULD BE LOADED AND RECEIVING UPDATES');
}
if (testLabel._suspendNativeUpdatesCount) {
console.log('testLabel SHOULD BE LOADED AND RECEIVING UPDATES');
}
// console.log("onTap");
// alert("onTap");
}
let ignoreInput = false;

export function toggleReusable(args: EventData) {
if (ignoreInput) {
return;
}
ignoreInput = true;
setTimeout(() => (ignoreInput = false), 0); // hack to avoid gesture collision
const target: any = args.object;
target.reusable = !target.reusable;
console.log(`${target} is now ${target.reusable ? '' : 'NOT '}reusable`);
}

export function toggleVCReusable() {
reusableItem.reusable = !reusableItem.reusable;
updateVcToggleText();
}
37 changes: 37 additions & 0 deletions apps/ui/src/issues/issue-7469-page.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<Page
xmlns="http://schemas.nativescript.org/tns.xsd" class="page" loaded="pageLoaded" unloaded="pageUnloaded">
<StackLayout class="p-20">
<Button text="Swap locations" tap="test"/>
<Button id="vcToggle" text="" tap="toggleVCReusable"/>
<Label text="Longpress items to toggle reusability"></Label>
<Label id="fpslabel" text=""></Label>
<StackLayout id="reusableItem" loaded="makeReusable">
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<Label longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" text="abc"></Label>
<WebView longPress="toggleReusable" loaded="makeReusable" unloaded="onReusableUnloaded" width="100" height="100" src="https://google.com"></WebView>
</StackLayout>
<StackLayout id="stack1" class="stack1">
<Label text="Stack 1"></Label>
</StackLayout>
<StackLayout id="stack2" class="stack2">
<Label text="Stack 2"></Label>
</StackLayout>
</StackLayout>
</Page>
1 change: 1 addition & 0 deletions apps/ui/src/issues/main-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function loadExamples() {
examples.set('ng-repo-1626', 'issues/issue-ng-repo-1626-page');
examples.set('6439', 'issues/issue-6439-page');
examples.set('open-file-6895', 'issues/open-file-6895-page');
examples.set("7469", "issues/issue-7469-page");

return examples;
}
13 changes: 13 additions & 0 deletions packages/core/ui/core/view-base/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ export abstract class ViewBase extends Observable {
public nativeView: any;
public bindingContext: any;

/**
* Gets or sets if the view is reusable.
* Reusable views are not automatically destroyed when removed from the View tree.
*/
public reusable: boolean;

/**
* Gets the name of the constructor function for this instance. E.g. for a Button class this will return "Button".
*/
Expand Down Expand Up @@ -365,6 +371,13 @@ export abstract class ViewBase extends Observable {
*/
_tearDownUI(force?: boolean): void;

/**
* Tears down the UI of a reusable node by making it no longer reusable.
* @see _tearDownUI
* @param forceDestroyChildren Force destroy the children (even if they are reusable)
*/
destroyNode(forceDestroyChildren?: boolean): void;

/**
* Creates a native view.
* Returns either android.view.View or UIView.
Expand Down
Loading
0