mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(core): Shared Element Transitions (#10022)
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
<Button text="scroll-view" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||
<Button text="switch" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||
<Button text="touch-animations" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||
<Button text="transitions" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||
<Button text="vector-image" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||
<Button text="visibility-vs-hidden" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||
<Button text="fs-helper" tap="{{ viewDemo }}" class="btn btn-primary btn-view-demo" />
|
||||
|
||||
32
apps/toolbox/src/pages/transitions.ts
Normal file
32
apps/toolbox/src/pages/transitions.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { Observable, EventData, Page, ShowModalOptions, SharedTransition, ModalTransition, PageTransition, FadeTransition, SlideTransition } from '@nativescript/core';
|
||||
let page: Page;
|
||||
|
||||
export function navigatingTo(args: EventData) {
|
||||
page = <Page>args.object;
|
||||
page.bindingContext = new TransitionsModel();
|
||||
}
|
||||
|
||||
export class TransitionsModel extends Observable {
|
||||
open(args: EventData) {
|
||||
const type = (<any>args.object).type;
|
||||
let moduleName: string;
|
||||
switch (type) {
|
||||
case '1':
|
||||
moduleName = `pages/transitions/transition-example`;
|
||||
break;
|
||||
case '2':
|
||||
moduleName = `pages/transitions/transition-page-modal-example`;
|
||||
break;
|
||||
}
|
||||
page.frame.navigate({
|
||||
moduleName,
|
||||
transition: SharedTransition.custom(new PageTransition(), {
|
||||
interactive: {
|
||||
dismiss: {
|
||||
finishThreshold: 0.5,
|
||||
},
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
13
apps/toolbox/src/pages/transitions.xml
Normal file
13
apps/toolbox/src/pages/transitions.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Transitions" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout rows="*,auto,*" class="p-20">
|
||||
<StackLayout row="1">
|
||||
<Button text="Open Testing Examples" class="btn btn-primary btn-view-demo" tap="{{open}}" type="1" />
|
||||
<Button text="Open Page and Modal Example" class="btn btn-primary btn-view-demo" tap="{{open}}" type="2" />
|
||||
</StackLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Observable, EventData, Page, NavigatedData } from '@nativescript/core';
|
||||
let page: Page;
|
||||
|
||||
export function navigatingTo(args: NavigatedData) {
|
||||
bindPage(args, args.context);
|
||||
}
|
||||
|
||||
let closeCallback;
|
||||
|
||||
export function onShownModally(args) {
|
||||
bindPage(args, args.context);
|
||||
closeCallback = args.closeCallback;
|
||||
}
|
||||
|
||||
function bindPage(args, context: any) {
|
||||
page = <Page>args.object;
|
||||
page.bindingContext = new TransitionsModel(context);
|
||||
}
|
||||
|
||||
export class TransitionsModel extends Observable {
|
||||
example1 = true;
|
||||
example2: boolean;
|
||||
example3: boolean;
|
||||
dynamicTag: string;
|
||||
constructor(options: { isModal?: boolean; example2?: boolean; example3?: boolean; dynamicTag?: string }) {
|
||||
super();
|
||||
this.example1 = options.example2 || options.example3 ? false : true;
|
||||
this.example2 = options.example2;
|
||||
this.example3 = options.example3;
|
||||
this.dynamicTag = options.dynamicTag;
|
||||
}
|
||||
close() {
|
||||
if (closeCallback) {
|
||||
closeCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" shownModally="onShownModally" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Transitions Example Detail" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout>
|
||||
<Button text="Close" tap="{{close}}" visibility="{{ isModal ? 'visible' : 'collapsed' }}" horizontalAlignment="left" verticalAlignment="top" marginTop="20" marginLeft="20" />
|
||||
<ContentView width="80%" height="300" borderRadius="20" backgroundColor="green" sharedTransitionTag="fab" horizontalAlignment="center" verticalAlignment="top" marginTop="100" visibility="{{ example1 ? 'visible' : 'collapsed' }}" />
|
||||
|
||||
<GridLayout visibility="{{ example2 ? 'visible' : 'collapsed' }}">
|
||||
<ContentView width="200" height="200" borderRadius="100" backgroundColor="purple" sharedTransitionTag="shape1" verticalAlignment="top" horizontalAlignment="right" marginRight="20" marginTop="20" iosIgnoreSafeArea="true" />
|
||||
<ContentView width="80" height="80" borderRadius="40" backgroundColor="orange" sharedTransitionTag="shape2" verticalAlignment="top" horizontalAlignment="left" marginLeft="20" marginTop="20" iosIgnoreSafeArea="true" />
|
||||
<ContentView width="20" height="20" borderRadius="10" backgroundColor="brown" sharedTransitionTag="shape3" verticalAlignment="bottom" horizontalAlignment="right" marginRight="20" iosIgnoreSafeArea="true" />
|
||||
<ContentView width="150" height="150" borderRadius="75" backgroundColor="yellow" sharedTransitionTag="shape4" verticalAlignment="bottom" horizontalAlignment="left" marginLeft="20" iosIgnoreSafeArea="true" />
|
||||
</GridLayout>
|
||||
|
||||
<GridLayout visibility="{{ example3 ? 'visible' : 'collapsed' }}">
|
||||
<ContentView width="80%" height="200" borderRadius="20" backgroundColor="purple" sharedTransitionTag="{{dynamicTag}}" verticalAlignment="top" horizontalAlignment="center" marginRight="20" marginTop="20" iosIgnoreSafeArea="true" />
|
||||
</GridLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
||||
111
apps/toolbox/src/pages/transitions/transition-example.ts
Normal file
111
apps/toolbox/src/pages/transitions/transition-example.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { Observable, EventData, Page, ShowModalOptions, SharedTransition, ModalTransition, PageTransition, FadeTransition, SlideTransition, PropertyChangeData } from '@nativescript/core';
|
||||
let page: Page;
|
||||
// SharedTransition.DEBUG = true;
|
||||
export function navigatingTo(args: EventData) {
|
||||
page = <Page>args.object;
|
||||
page.bindingContext = new TransitionsModel();
|
||||
}
|
||||
|
||||
let updatedSegmentValue: number;
|
||||
if (typeof updatedSegmentValue === 'undefined') {
|
||||
updatedSegmentValue = 0;
|
||||
}
|
||||
export class TransitionsModel extends Observable {
|
||||
segmentSelectedIndex = updatedSegmentValue;
|
||||
|
||||
items = [
|
||||
{
|
||||
title: 'Homer',
|
||||
dynamicTag: 'dynamic1',
|
||||
},
|
||||
{
|
||||
title: 'Marge',
|
||||
dynamicTag: 'dynamic2',
|
||||
},
|
||||
{
|
||||
title: 'Bart',
|
||||
dynamicTag: 'dynamic3',
|
||||
},
|
||||
{
|
||||
title: 'Lisa',
|
||||
dynamicTag: 'dynamic4',
|
||||
},
|
||||
{
|
||||
title: 'Maggie',
|
||||
dynamicTag: 'dynamic5',
|
||||
},
|
||||
];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.on(Observable.propertyChangeEvent, (data: PropertyChangeData) => {
|
||||
if (data.propertyName === 'segmentSelectedIndex') {
|
||||
console.log('change segmentSelectedIndex--');
|
||||
console.log(data.value);
|
||||
updatedSegmentValue = data.value;
|
||||
this.segmentSelectedIndex = data.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
open(args) {
|
||||
const moduleName = `pages/transitions/transition-example-detail`;
|
||||
const context: any = {
|
||||
example2: !!args.object.example2,
|
||||
example3: !!args.object.example3,
|
||||
dynamicTag: args.object.dynamicTag,
|
||||
};
|
||||
page.frame.navigate({
|
||||
moduleName,
|
||||
context,
|
||||
transition: SharedTransition.custom(new PageTransition(), {
|
||||
interactive: {
|
||||
dismiss: {
|
||||
finishThreshold: 0.5,
|
||||
},
|
||||
},
|
||||
// pageEnd: {
|
||||
// duration: 3000
|
||||
// },
|
||||
// pageReturn: {
|
||||
// duration: 1000
|
||||
// }
|
||||
}),
|
||||
});
|
||||
|
||||
// Try modals as well:
|
||||
// context.isModal = true;
|
||||
// page.showModal(moduleName, {
|
||||
// context,
|
||||
// transition: SharedTransition.custom(new ModalTransition(), {
|
||||
// interactive: {
|
||||
// dismiss: {
|
||||
// finishThreshold: 0.5,
|
||||
// },
|
||||
// },
|
||||
// pageStart: {
|
||||
// y: 200,
|
||||
// // duration: 400,
|
||||
// },
|
||||
// pageReturn: {
|
||||
// y: 100,
|
||||
// // duration: 500,
|
||||
// },
|
||||
// }),
|
||||
// closeCallback(args) {
|
||||
// // console.log('close modal callback', args);
|
||||
// },
|
||||
// } as ShowModalOptions);
|
||||
}
|
||||
|
||||
onItemTap(args) {
|
||||
const item = this.items[args.index];
|
||||
console.log(item);
|
||||
this.open({
|
||||
object: {
|
||||
example3: true,
|
||||
dynamicTag: item.dynamicTag,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
40
apps/toolbox/src/pages/transitions/transition-example.xml
Normal file
40
apps/toolbox/src/pages/transitions/transition-example.xml
Normal file
@@ -0,0 +1,40 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Transitions Example 1" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout rows="auto,*">
|
||||
<SegmentedBar sharedTransitionTag="segmentbar" horizontalAlignment="center" selectedIndex="{{ segmentSelectedIndex }}" marginTop="20">
|
||||
<SegmentedBarItem title="Example A" />
|
||||
<SegmentedBarItem title="Example B" />
|
||||
<SegmentedBarItem title="Example C" />
|
||||
</SegmentedBar>
|
||||
|
||||
<!-- Example A: Fab -->
|
||||
<ContentView visibility="{{ segmentSelectedIndex === 0 ? 'visible' : 'collapsed' }}" row="1" width="75" height="75" borderRadius="38" backgroundColor="#65adf1" sharedTransitionTag="fab" horizontalAlignment="right" verticalAlignment="bottom" marginBottom="20" marginRight="30" tap="{{open}}" sharedTransitionIgnore="{{segmentSelectedIndex!==0}}" />
|
||||
|
||||
<!-- Example B: Multiple Shapes in Layout Containers -->
|
||||
<GridLayout row="1" visibility="{{ segmentSelectedIndex === 1 ? 'visible' : 'collapsed' }}" tap="{{open}}" marginTop="20" example2="true">
|
||||
<GridLayout rows="" columns="*,auto,*,auto,*,auto,*,auto,*" verticalAlignment="bottom" marginBottom="20">
|
||||
<ContentView col="1" width="40" height="40" borderRadius="20" backgroundColor="#65adf1" sharedTransitionTag="shape1" sharedTransitionIgnore="{{segmentSelectedIndex!==1}}" />
|
||||
<ContentView col="3" width="40" height="40" borderRadius="20" backgroundColor="#65adf1" sharedTransitionTag="shape2" sharedTransitionIgnore="{{segmentSelectedIndex!==1}}" />
|
||||
<ContentView col="5" width="40" height="40" borderRadius="20" backgroundColor="#65adf1" sharedTransitionTag="shape3" sharedTransitionIgnore="{{segmentSelectedIndex!==1}}" />
|
||||
<ContentView col="7" width="40" height="40" borderRadius="20" backgroundColor="#65adf1" sharedTransitionTag="shape4" sharedTransitionIgnore="{{segmentSelectedIndex!==1}}" />
|
||||
</GridLayout>
|
||||
</GridLayout>
|
||||
|
||||
|
||||
<!-- Example C: Dynamic sharedTransitionTags passed around -->
|
||||
<GridLayout row="2" visibility="{{ segmentSelectedIndex === 2 ? 'visible' : 'collapsed' }}" marginTop="20" example3="true">
|
||||
<ListView items="{{ items }}" itemTap="{{onItemTap}}" separatorColor="transparent">
|
||||
<ListView.itemTemplate>
|
||||
<GridLayout columns="auto,*" padding="8">
|
||||
<ContentView marginLeft="10" width="40" height="40" borderRadius="20" backgroundColor="#65adf1" sharedTransitionTag="{{dynamicTag}}" />
|
||||
<Label col="1" marginLeft="10" text="{{ title }}" />
|
||||
</GridLayout>
|
||||
</ListView.itemTemplate>
|
||||
</ListView>
|
||||
</GridLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
||||
@@ -0,0 +1,56 @@
|
||||
import { Observable, EventData, Page, ShowModalOptions, SharedTransition, ModalTransition, PageTransition, FadeTransition, SlideTransition } from '@nativescript/core';
|
||||
let page: Page;
|
||||
|
||||
export function navigatingTo(args: EventData) {
|
||||
page = <Page>args.object;
|
||||
page.bindingContext = new TransitionsModel();
|
||||
}
|
||||
|
||||
// Could create a complete custom example which extends some of the built in options
|
||||
// class SampleCustomModalTransition extends ModalTransition implements TransitionType {
|
||||
|
||||
// }
|
||||
// SharedTransition.DEBUG = true;
|
||||
export class TransitionsModel extends Observable {
|
||||
open() {
|
||||
page.frame.navigate({
|
||||
moduleName: `pages/transitions/transitions-detail`,
|
||||
transition: SharedTransition.custom(new PageTransition(), {
|
||||
interactive: {
|
||||
dismiss: {
|
||||
finishThreshold: 0.5,
|
||||
},
|
||||
},
|
||||
// toPageStart: {
|
||||
// duration: 1000,
|
||||
// },
|
||||
// fromPageEnd: {
|
||||
// duration: 500,
|
||||
// },
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
openModal() {
|
||||
page.showModal('pages/transitions/transitions-modal', {
|
||||
transition: SharedTransition.custom(new ModalTransition(), {
|
||||
interactive: {
|
||||
dismiss: {
|
||||
finishThreshold: 0.5,
|
||||
},
|
||||
},
|
||||
pageStart: {
|
||||
y: 200,
|
||||
// duration: 400,
|
||||
},
|
||||
pageReturn: {
|
||||
y: 100,
|
||||
// duration: 500,
|
||||
},
|
||||
}),
|
||||
closeCallback(args) {
|
||||
// console.log('close modal callback', args);
|
||||
},
|
||||
} as ShowModalOptions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Transitions" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout rows="*,auto,auto,*">
|
||||
<GridLayout row="1" rows="auto,auto" tap="{{ open }}">
|
||||
<Image sharedTransitionTag="image" src="https://cdn.pixabay.com/photo/2012/08/27/14/19/mountains-55067__340.png" width="100" />
|
||||
<Label row="1" text="Open Page" class="text-center" color="black" />
|
||||
</GridLayout>
|
||||
|
||||
<GridLayout row="2" rows="auto,auto,auto,auto" tap="{{ openModal }}" marginTop="50">
|
||||
<Image sharedTransitionTag="image-modal" src="https://cdn.pixabay.com/photo/2012/08/27/14/19/mountains-55067__340.png" width="100" />
|
||||
<Label row="1" text="NativeScript Rocks!" sharedTransitionTag="open-modal-label" class="text-center" color="black" />
|
||||
|
||||
<ContentView row="2" sharedTransitionTag="open-modal-box1" borderWidth="5" borderColor="yellow" marginTop="20" width="50" height="50" borderRadius="999" backgroundColor="purple" />
|
||||
<ContentView row="3" sharedTransitionTag="open-modal-box2" marginTop="20" width="20" height="20" borderRadius="999" backgroundColor="orange" />
|
||||
<ContentView row="3" sharedTransitionTag="open-modal-box3" marginTop="20" width="20" height="20" borderRadius="999" backgroundColor="red" horizontalAlignment="left" marginLeft="100" />
|
||||
<ContentView row="4" sharedTransitionTag="open-modal-box4" marginTop="20" width="20" height="20" borderRadius="999" backgroundColor="pink" horizontalAlignment="right" marginRight="100" />
|
||||
</GridLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
||||
10
apps/toolbox/src/pages/transitions/transitions-detail.ts
Normal file
10
apps/toolbox/src/pages/transitions/transitions-detail.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Observable, EventData, Page } from '@nativescript/core';
|
||||
|
||||
let page: Page;
|
||||
|
||||
export function navigatingTo(args: EventData) {
|
||||
page = <Page>args.object;
|
||||
page.bindingContext = new TransitionsModel();
|
||||
}
|
||||
|
||||
export class TransitionsModel extends Observable {}
|
||||
19
apps/toolbox/src/pages/transitions/transitions-detail.xml
Normal file
19
apps/toolbox/src/pages/transitions/transitions-detail.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="navigatingTo" class="page">
|
||||
<Page.actionBar>
|
||||
<ActionBar title="Transition Detail" icon="" class="action-bar">
|
||||
</ActionBar>
|
||||
</Page.actionBar>
|
||||
|
||||
<GridLayout rows="auto,auto,*" columns="*" verticalAlignment="top">
|
||||
<Image row="1" sharedTransitionTag="image" src="https://cdn.pixabay.com/photo/2012/08/27/14/19/mountains-55067__340.png" height="230" verticalAlignment="top" marginTop="10" />
|
||||
|
||||
<GridLayout row="2" rows="auto,auto,auto">
|
||||
<Label text="Opened Navigated Page" verticalAlignment="top" marginTop="20" class="text-center" fontSize="28" color="black" />
|
||||
|
||||
<ContentView row="2" sharedTransitionTag="open-modal-box1" marginTop="20" width="200" height="200" borderRadius="100" backgroundColor="purple" />
|
||||
<ContentView row="1" sharedTransitionTag="open-modal-box2" marginTop="20" width="75" height="75" borderRadius="37" backgroundColor="orange" />
|
||||
<ContentView row="2" sharedTransitionTag="open-modal-box3" marginTop="20" width="30" height="30" borderRadius="15" backgroundColor="red" horizontalAlignment="right" marginRight="50" />
|
||||
<ContentView row="1" sharedTransitionTag="open-modal-box4" marginTop="20" width="30" height="30" borderRadius="15" backgroundColor="pink" horizontalAlignment="left" marginLeft="50" />
|
||||
</GridLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
||||
22
apps/toolbox/src/pages/transitions/transitions-modal.ts
Normal file
22
apps/toolbox/src/pages/transitions/transitions-modal.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Observable, ShownModallyData, LoadEventData, Page, ShowModalOptions } from '@nativescript/core';
|
||||
|
||||
let page: Page;
|
||||
let closeCallback: Function;
|
||||
export function onShownModally(args: ShownModallyData) {
|
||||
closeCallback = args.closeCallback;
|
||||
|
||||
if (args.context) {
|
||||
args.context.shownModally = true;
|
||||
}
|
||||
}
|
||||
|
||||
export function onLoaded(args: LoadEventData) {
|
||||
page = args.object as Page;
|
||||
page.bindingContext = new TransitionModalPage();
|
||||
}
|
||||
|
||||
export class TransitionModalPage extends Observable {
|
||||
close() {
|
||||
closeCallback();
|
||||
}
|
||||
}
|
||||
16
apps/toolbox/src/pages/transitions/transitions-modal.xml
Normal file
16
apps/toolbox/src/pages/transitions/transitions-modal.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="onLoaded" shownModally="onShownModally">
|
||||
|
||||
<GridLayout rows="auto,auto,*" columns="*" verticalAlignment="top">
|
||||
<Button text="Close" tap="{{close}}" horizontalAlignment="right" marginRight="10" />
|
||||
<Image row="1" sharedTransitionTag="image-modal" src="https://cdn.pixabay.com/photo/2012/08/27/14/19/mountains-55067__340.png" height="230" verticalAlignment="top" marginTop="10" />
|
||||
|
||||
<GridLayout row="2" rows="auto,auto,auto">
|
||||
<Label text="Opened Modal" verticalAlignment="top" marginTop="20" class="text-center" fontSize="28" color="black" />
|
||||
|
||||
<ContentView row="1" sharedTransitionTag="open-modal-box2" marginTop="20" width="75" height="75" borderRadius="37" backgroundColor="orange" />
|
||||
<ContentView row="2" sharedTransitionTag="open-modal-box1" marginTop="20" width="200" height="200" borderRadius="100" backgroundColor="purple" />
|
||||
<ContentView row="2" sharedTransitionTag="open-modal-box3" marginTop="20" width="30" height="30" borderRadius="15" backgroundColor="red" horizontalAlignment="right" marginRight="50" />
|
||||
<ContentView row="1" sharedTransitionTag="open-modal-box4" marginTop="20" width="30" height="30" borderRadius="15" backgroundColor="pink" horizontalAlignment="left" marginLeft="50" />
|
||||
</GridLayout>
|
||||
</GridLayout>
|
||||
</Page>
|
||||
Reference in New Issue
Block a user