mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
feat(core): shared element transitions with api for ios
This commit is contained in:
@@ -1,2 +1,2 @@
|
||||
<Frame defaultPage="main-page">
|
||||
<Frame defaultPage="pages/transitions">
|
||||
</Frame>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
47
apps/toolbox/src/pages/transitions.ts
Normal file
47
apps/toolbox/src/pages/transitions.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { Observable, EventData, Page, ShowModalOptions, SharedTransition, ModalTransition, TransitionType, Screen } from '@nativescript/core';
|
||||
// import { DetailTransition } from './transitions/detail';
|
||||
let page: Page;
|
||||
|
||||
export function navigatingTo(args: EventData) {
|
||||
page = <Page>args.object;
|
||||
page.bindingContext = new TransitionsModel();
|
||||
}
|
||||
|
||||
// class SampleCustomModalTransition extends ModalTransition implements TransitionType {
|
||||
|
||||
// }
|
||||
export class TransitionsModel extends Observable {
|
||||
open() {
|
||||
// const detailTransition = new DetailTransition(400, global.isIOS ? UIViewAnimationCurve.EaseInOut : null);
|
||||
// detailTransition.page = page;
|
||||
page.frame.navigate({
|
||||
moduleName: `pages/transitions/transitions-detail`,
|
||||
// transition: {
|
||||
// instance: detailTransition,
|
||||
// },
|
||||
});
|
||||
}
|
||||
|
||||
openModal() {
|
||||
page.showModal('pages/transitions/transitions-modal', {
|
||||
context: {},
|
||||
transition: {
|
||||
instance: SharedTransition.configure({
|
||||
page,
|
||||
instance: new ModalTransition(),
|
||||
incomingViewStart: {
|
||||
y: 200,
|
||||
duration: 1000,
|
||||
},
|
||||
dismissViewEnd: {
|
||||
y: 100,
|
||||
duration: 500,
|
||||
},
|
||||
}),
|
||||
},
|
||||
closeCallback(args) {
|
||||
console.log('close modal callback', args);
|
||||
},
|
||||
} as ShowModalOptions);
|
||||
}
|
||||
}
|
||||
23
apps/toolbox/src/pages/transitions.xml
Normal file
23
apps/toolbox/src/pages/transitions.xml
Normal file
@@ -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" />
|
||||
</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="Open Modal" sharedTransitionTag="open-modal-label" class="text-center" />
|
||||
<ContentView row="2" sharedTransitionTag="open-modal-box" marginTop="20" width="50" height="50" borderRadius="25" backgroundColor="purple" />
|
||||
<ContentView row="3" sharedTransitionTag="open-modal-box2" marginTop="20" width="15" height="15" borderRadius="7" backgroundColor="orange" />
|
||||
<ContentView row="3" sharedTransitionTag="open-modal-box3" marginTop="20" width="15" height="15" borderRadius="7" backgroundColor="red" horizontalAlignment="left" marginLeft="100" />
|
||||
<ContentView row="4" sharedTransitionTag="open-modal-box4" marginTop="20" width="15" height="15" borderRadius="7" 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 {}
|
||||
10
apps/toolbox/src/pages/transitions/transitions-detail.xml
Normal file
10
apps/toolbox/src/pages/transitions/transitions-detail.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<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="*" columns="auto,*" verticalAlignment="top">
|
||||
<Image row="0" sharedTransitionTag="image" src="https://cdn.pixabay.com/photo/2012/08/27/14/19/mountains-55067__340.png" width="100%" />
|
||||
</GridLayout>
|
||||
</Page>
|
||||
24
apps/toolbox/src/pages/transitions/transitions-modal.ts
Normal file
24
apps/toolbox/src/pages/transitions/transitions-modal.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { Observable, ShownModallyData, LoadEventData, Page, ShowModalOptions } from '@nativescript/core';
|
||||
|
||||
let page: Page;
|
||||
let closeCallback: Function;
|
||||
export function onShownModally(args: ShownModallyData) {
|
||||
console.log('page shown modally');
|
||||
|
||||
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-box" 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>
|
||||
1
packages/core/accessibility/index.d.ts
vendored
1
packages/core/accessibility/index.d.ts
vendored
@@ -1,5 +1,4 @@
|
||||
import type { Page } from '../ui/page';
|
||||
import type { ViewBase } from '../ui/core/view-base';
|
||||
import type { View } from '../ui/core/view';
|
||||
import type { AndroidAccessibilityEvent } from './accessibility-types';
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ function ensureNativeClasses() {
|
||||
});
|
||||
}
|
||||
|
||||
export function setupAccessibleView(view: Partial<ViewBase>): void {
|
||||
export function setupAccessibleView(view: View): void {
|
||||
const uiView = view.nativeViewProtected as UIView;
|
||||
if (!uiView) {
|
||||
return;
|
||||
|
||||
19
packages/core/ui/core/view-base/index.d.ts
vendored
19
packages/core/ui/core/view-base/index.d.ts
vendored
@@ -8,7 +8,7 @@ import { Page } from '../../page';
|
||||
import { Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf } from '../../layouts/flexbox-layout';
|
||||
import { Length } from '../../styling/style-properties';
|
||||
import { DOMNode } from '../../../debugger/dom-node';
|
||||
import type { CustomTransitionModal } from '../../transition';
|
||||
import type { ModalTransition } from '../../transition/modal-transition';
|
||||
|
||||
/**
|
||||
* Iterates through all child views (via visual tree) and executes a function.
|
||||
@@ -43,9 +43,17 @@ export function getViewById(view: ViewBase, id: string): ViewBase;
|
||||
*/
|
||||
export function getViewByDomId(view: ViewBase, domId: number): ViewBase;
|
||||
|
||||
export interface ModalTransition {
|
||||
/**
|
||||
* Gets a child view by selector.
|
||||
* @param view - The parent (container) view of the view to look for.
|
||||
* @param selector - The selector of the view to look for.
|
||||
* Returns an instance of a view (if found), otherwise undefined.
|
||||
*/
|
||||
export function querySelectorAll(view: ViewBase, selector: string): Array<ViewBase>;
|
||||
|
||||
export interface ModalTransitionType {
|
||||
name?: string;
|
||||
instance?: CustomTransitionModal;
|
||||
instance?: ModalTransition;
|
||||
duration?: number;
|
||||
curve?: any;
|
||||
}
|
||||
@@ -298,6 +306,11 @@ export abstract class ViewBase extends Observable {
|
||||
*/
|
||||
public className: string;
|
||||
|
||||
/**
|
||||
* Gets or sets the shared transition tag for animated view transitions
|
||||
*/
|
||||
public sharedTransitionTag: string;
|
||||
|
||||
/**
|
||||
* Gets owner page. This is a read-only property.
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Trace } from '../../../trace';
|
||||
import { Observable, PropertyChangeData, WrappedValue } from '../../../data/observable';
|
||||
import { Style } from '../../styling/style';
|
||||
import { paddingTopProperty, paddingRightProperty, paddingBottomProperty, paddingLeftProperty } from '../../styling/style-properties';
|
||||
import type { CustomTransitionModal } from '../../transition';
|
||||
import type { ModalTransition } from '../../transition/modal-transition';
|
||||
|
||||
// TODO: Remove this import!
|
||||
import { getClass } from '../../../utils/types';
|
||||
@@ -38,9 +38,9 @@ function ensureStyleScopeModule() {
|
||||
|
||||
const defaultBindingSource = {};
|
||||
|
||||
export interface ModalTransition {
|
||||
export interface ModalTransitionType {
|
||||
name?: string;
|
||||
instance?: CustomTransitionModal;
|
||||
instance?: ModalTransition;
|
||||
duration?: number;
|
||||
curve?: any;
|
||||
}
|
||||
@@ -74,7 +74,7 @@ export interface ShowModalOptions {
|
||||
/**
|
||||
* An optional custom transition effect
|
||||
*/
|
||||
transition?: ModalTransition;
|
||||
transition?: ModalTransitionType;
|
||||
|
||||
/**
|
||||
* An optional parameter that specify options specific to iOS as an object.
|
||||
@@ -181,6 +181,30 @@ export function getViewByDomId(view: ViewBaseDefinition, domId: number): ViewBas
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// TODO: allow all selector types (just using attributes now)
|
||||
export function querySelectorAll(view: ViewBaseDefinition, selector: string): Array<ViewBaseDefinition> {
|
||||
if (!view) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const retVal: Array<ViewBaseDefinition> = [];
|
||||
if (view[selector]) {
|
||||
retVal.push(view);
|
||||
}
|
||||
|
||||
const descendantsCallback = function (child: ViewBaseDefinition): boolean {
|
||||
if (child[selector]) {
|
||||
retVal.push(child);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
eachDescendant(view, descendantsCallback);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
export function eachDescendant(view: ViewBaseDefinition, callback: (child: ViewBaseDefinition) => boolean) {
|
||||
if (!callback || !view) {
|
||||
return;
|
||||
@@ -283,6 +307,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
public id: string;
|
||||
public className: string;
|
||||
public sharedTransitionTag: string;
|
||||
|
||||
public _domId: number;
|
||||
public _context: any;
|
||||
@@ -453,7 +478,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition
|
||||
|
||||
return true;
|
||||
});
|
||||
setupAccessibleView(this);
|
||||
setupAccessibleView(<any>this);
|
||||
|
||||
this._emit('loaded');
|
||||
}
|
||||
|
||||
@@ -932,41 +932,41 @@ class UIViewControllerTransitioningDelegateImpl extends NSObject implements UIVi
|
||||
}
|
||||
|
||||
animationControllerForDismissedController?(dismissed: UIViewController): UIViewControllerAnimatedTransitioning {
|
||||
const owner = this.owner?.get();
|
||||
if (owner?.dismissedController) {
|
||||
return owner.dismissedController(dismissed);
|
||||
const owner = this.owner?.deref();
|
||||
if (owner?.iosDismissedController) {
|
||||
return owner.iosDismissedController(dismissed);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
animationControllerForPresentedControllerPresentingControllerSourceController?(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIViewControllerAnimatedTransitioning {
|
||||
const owner = this.owner?.get();
|
||||
if (owner?.presentedController) {
|
||||
return owner.presentedController(presented, presenting, source);
|
||||
const owner = this.owner?.deref();
|
||||
if (owner?.iosPresentedController) {
|
||||
return owner.iosPresentedController(presented, presenting, source);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
interactionControllerForDismissal?(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
|
||||
const owner = this.owner?.get();
|
||||
if (owner?.interactionDismiss) {
|
||||
return owner.interactionDismiss(animator);
|
||||
const owner = this.owner?.deref();
|
||||
if (owner?.iosInteractionDismiss) {
|
||||
return owner.iosInteractionDismiss(animator);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
interactionControllerForPresentation?(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
|
||||
const owner = this.owner?.get();
|
||||
if (owner?.interactionPresented) {
|
||||
return owner.interactionPresented(animator);
|
||||
const owner = this.owner?.deref();
|
||||
if (owner?.iosInteractionPresented) {
|
||||
return owner.iosInteractionPresented(animator);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
presentationControllerForPresentedViewControllerPresentingViewControllerSourceViewController?(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIPresentationController {
|
||||
const owner = this.owner?.get();
|
||||
if (owner?.presentedViewController) {
|
||||
return owner.presentedViewController(presented, presenting, source);
|
||||
const owner = this.owner?.deref();
|
||||
if (owner?.iosPresentedViewController) {
|
||||
return owner.iosPresentedViewController(presented, presenting, source);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ export { ContentView } from './content-view';
|
||||
export { Binding } from './core/bindable';
|
||||
export type { BindingOptions } from './core/bindable';
|
||||
export { ControlStateChangeListener } from './core/control-state-change';
|
||||
export { ViewBase, eachDescendant, getAncestor, getViewById, booleanConverter } from './core/view-base';
|
||||
export { ViewBase, eachDescendant, getAncestor, getViewById, booleanConverter, querySelectorAll } from './core/view-base';
|
||||
export type { ShowModalOptions } from './core/view-base';
|
||||
export { View, CSSType, ContainerView, ViewHelper, IOSHelper, isUserInteractionEnabledProperty, PseudoClassHandler, CustomLayoutView } from './core/view';
|
||||
export type { Template, KeyedTemplate, ShownModallyData, AddArrayFromBuilder, AddChildFromBuilder, Size } from './core/view';
|
||||
@@ -74,6 +74,9 @@ export { Span } from './text-base/span';
|
||||
export { TextField } from './text-field';
|
||||
export { TextView } from './text-view';
|
||||
export { TimePicker } from './time-picker';
|
||||
export { Transition, CustomTransitionModal } from './transition';
|
||||
export { Transition } from './transition';
|
||||
export { ModalTransition } from './transition/modal-transition';
|
||||
export { SharedTransition, SharedTransitionAnimationType } from './transition/shared-transition';
|
||||
export type { TransitionType } from './transition';
|
||||
export { WebView } from './web-view';
|
||||
export type { LoadEventData, WebViewNavigationType } from './web-view';
|
||||
|
||||
@@ -8,6 +8,7 @@ import { PageBase, actionBarHiddenProperty, statusBarStyleProperty } from './pag
|
||||
import { profile } from '../../profiling';
|
||||
import { iOSNativeHelper, layout } from '../../utils';
|
||||
import { getLastFocusedViewOnPage, isAccessibilityServiceEnabled } from '../../accessibility';
|
||||
import { SharedTransition } from '../transition/shared-transition';
|
||||
|
||||
export * from './page-common';
|
||||
|
||||
@@ -430,6 +431,8 @@ export class Page extends PageBase {
|
||||
|
||||
// Make transitions look good
|
||||
controller.view.backgroundColor = this._backgroundColor;
|
||||
console.log('here for Page:', this.viewController);
|
||||
SharedTransition.addPageToTop(this);
|
||||
}
|
||||
|
||||
createNativeView() {
|
||||
@@ -465,6 +468,7 @@ export class Page extends PageBase {
|
||||
|
||||
public onLoaded(): void {
|
||||
super.onLoaded();
|
||||
console.log('page loaded');
|
||||
if (this.hasActionBar) {
|
||||
this.actionBar.update();
|
||||
}
|
||||
|
||||
45
packages/core/ui/page/page-common.d.ts
vendored
45
packages/core/ui/page/page-common.d.ts
vendored
@@ -1,45 +0,0 @@
|
||||
import { Page as PageDefinition } from '.';
|
||||
import { ContentView } from '../content-view';
|
||||
import { Frame } from '../frame';
|
||||
import { KeyframeAnimationInfo } from '../animation';
|
||||
import { NavigatedData } from '.';
|
||||
import { Color } from '../../color';
|
||||
import { ActionBar } from '../action-bar';
|
||||
import { View } from '../core/view';
|
||||
export declare class PageBase extends ContentView {
|
||||
static navigatingToEvent: string;
|
||||
static navigatedToEvent: string;
|
||||
static navigatingFromEvent: string;
|
||||
static navigatedFromEvent: string;
|
||||
_frame: Frame;
|
||||
actionBarHidden: boolean;
|
||||
enableSwipeBackNavigation: boolean;
|
||||
backgroundSpanUnderStatusBar: boolean;
|
||||
hasActionBar: boolean;
|
||||
readonly navigationContext: any;
|
||||
|
||||
actionBar: ActionBar;
|
||||
|
||||
statusBarStyle: 'light' | 'dark';
|
||||
androidStatusBarBackground: Color;
|
||||
|
||||
readonly page: PageDefinition;
|
||||
|
||||
_addChildFromBuilder(name: string, value: any): void;
|
||||
|
||||
getKeyframeAnimationWithName(animationName: string): KeyframeAnimationInfo;
|
||||
|
||||
readonly frame: Frame;
|
||||
|
||||
createNavigatedData(eventName: string, isBackNavigation: boolean): NavigatedData;
|
||||
|
||||
onNavigatingTo(context: any, isBackNavigation: boolean, bindingContext?: any): void;
|
||||
|
||||
onNavigatedTo(isBackNavigation: boolean): void;
|
||||
|
||||
onNavigatingFrom(isBackNavigation: boolean): void;
|
||||
|
||||
onNavigatedFrom(isBackNavigation: boolean): void;
|
||||
|
||||
eachChildView(callback: (child: View) => boolean): void;
|
||||
}
|
||||
@@ -1,25 +1,28 @@
|
||||
// Types.
|
||||
import { _resolveAnimationCurve } from '../animation';
|
||||
import { _resolveAnimationCurve } from '../animation';
|
||||
import lazy from '../../utils/lazy';
|
||||
import type { Transition as TransitionType } from '.';
|
||||
|
||||
export type { TransitionType } from '.';
|
||||
|
||||
const _defaultInterpolator = lazy(() => new android.view.animation.AccelerateDecelerateInterpolator());
|
||||
|
||||
let transitionId = 0;
|
||||
export class Transition {
|
||||
export class Transition implements TransitionType {
|
||||
static AndroidTransitionType = {
|
||||
enter: 'enter',
|
||||
exit: 'exit',
|
||||
popEnter: 'popEnter',
|
||||
popExit: 'popExit',
|
||||
};
|
||||
id: number;
|
||||
private _duration: number;
|
||||
private _interpolator: android.view.animation.Interpolator;
|
||||
private _id: number;
|
||||
|
||||
constructor(duration: number, curve?: any) {
|
||||
constructor(duration: number = 350, curve?: any) {
|
||||
this._duration = duration;
|
||||
this._interpolator = curve ? _resolveAnimationCurve(curve) : _defaultInterpolator();
|
||||
this._id = transitionId++;
|
||||
transitionId++;
|
||||
this.id = transitionId;
|
||||
}
|
||||
|
||||
public getDuration(): number {
|
||||
@@ -39,8 +42,6 @@ export class Transition {
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return `Transition@${this._id}`;
|
||||
return `Transition@${this.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomTransitionModal extends Transition {}
|
||||
|
||||
39
packages/core/ui/transition/index.d.ts
vendored
39
packages/core/ui/transition/index.d.ts
vendored
@@ -1,21 +1,24 @@
|
||||
export declare class Transition {
|
||||
static AndroidTransitionType: { enter: string; exit: string; popEnter: string; popExit: string };
|
||||
constructor(duration: number, nativeCurve?: any /* UIViewAnimationCurve | string | CubicBezierAnimationCurve | android.view.animation.Interpolator | android.view.animation.LinearInterpolator */);
|
||||
public getDuration(): number;
|
||||
public getCurve(): any;
|
||||
public animateIOSTransition(transitionContext: any /*UIViewControllerContextTransitioning */, fromViewCtrl: any /* UIViewController */, toViewCtrl: any /* UIViewController */, operation: any /* UINavigationControllerOperation */): void;
|
||||
public createAndroidAnimator(transitionType: string): any;
|
||||
public toString(): string;
|
||||
export interface TransitionType {
|
||||
id: number;
|
||||
|
||||
iosDismissedController?(dismissed: any /* UIViewController */): any /* UIViewControllerAnimatedTransitioning */;
|
||||
|
||||
iosPresentedController?(presented: any /* UIViewController */, presenting: any /* UIViewController */, source: any /* UIViewController */): any /* UIViewControllerAnimatedTransitioning */;
|
||||
|
||||
iosInteractionDismiss?(animator: any /* UIViewControllerAnimatedTransitioning */): any /* UIViewControllerInteractiveTransitioning */;
|
||||
|
||||
iosInteractionPresented?(animator: any /* UIViewControllerAnimatedTransitioning */): any /* UIViewControllerInteractiveTransitioning */;
|
||||
|
||||
iosPresentedViewController?(presented: any /* UIViewController */, presenting: any /* UIViewController */, source: any /* UIViewController */): any /* UIPresentationController */;
|
||||
}
|
||||
|
||||
export declare class CustomTransitionModal extends Transition {
|
||||
dismissedController?(dismissed: any /* UIViewController */): any /* UIViewControllerAnimatedTransitioning */;
|
||||
|
||||
presentedController?(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIViewControllerAnimatedTransitioning;
|
||||
|
||||
interactionDismiss?(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning;
|
||||
|
||||
interactionPresented?(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning;
|
||||
|
||||
presentedViewController?(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIPresentationController;
|
||||
export declare class Transition implements TransitionType {
|
||||
id: number;
|
||||
static AndroidTransitionType?: { enter?: string; exit?: string; popEnter?: string; popExit?: string };
|
||||
constructor(duration?: number, nativeCurve?: any /* UIViewAnimationCurve | string | CubicBezierAnimationCurve | android.view.animation.Interpolator | android.view.animation.LinearInterpolator */);
|
||||
getDuration(): number;
|
||||
getCurve(): any;
|
||||
animateIOSTransition(transitionContext: any /*UIViewControllerContextTransitioning */, fromViewCtrl: any /* UIViewController */, toViewCtrl: any /* UIViewController */, operation: any /* UINavigationControllerOperation */): void;
|
||||
createAndroidAnimator(transitionType: string): any;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
let transitionId = 0;
|
||||
export class Transition {
|
||||
import type { TransitionType } from '.';
|
||||
|
||||
export type { TransitionType } from '.';
|
||||
|
||||
let transitionId = 0;
|
||||
export class Transition implements TransitionType {
|
||||
static AndroidTransitionType = {};
|
||||
id: number;
|
||||
private _duration: number;
|
||||
private _curve: UIViewAnimationCurve;
|
||||
private _id: number;
|
||||
|
||||
constructor(duration: number, curve: UIViewAnimationCurve = UIViewAnimationCurve.EaseInOut) {
|
||||
constructor(duration: number = 350, nativeCurve: UIViewAnimationCurve = UIViewAnimationCurve.EaseInOut) {
|
||||
this._duration = duration ? duration / 1000 : 0.35;
|
||||
this._curve = curve;
|
||||
this._id = transitionId++;
|
||||
this._curve = nativeCurve;
|
||||
transitionId++;
|
||||
this.id = transitionId;
|
||||
}
|
||||
|
||||
public getDuration(): number {
|
||||
@@ -28,29 +33,6 @@ export class Transition {
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return `Transition@${this._id}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomTransitionModal extends Transition {
|
||||
// Extend this class to create your own
|
||||
dismissedController?(dismissed: UIViewController): UIViewControllerAnimatedTransitioning {
|
||||
return null;
|
||||
}
|
||||
|
||||
presentedController?(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIViewControllerAnimatedTransitioning {
|
||||
return null;
|
||||
}
|
||||
|
||||
interactionDismiss?(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
|
||||
return null;
|
||||
}
|
||||
|
||||
interactionPresented?(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
|
||||
return null;
|
||||
}
|
||||
|
||||
presentedViewController?(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIPresentationController {
|
||||
return null;
|
||||
return `Transition@${this.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
3
packages/core/ui/transition/modal-transition.android.ts
Normal file
3
packages/core/ui/transition/modal-transition.android.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Transition } from '.';
|
||||
|
||||
export class ModalTransition extends Transition {}
|
||||
3
packages/core/ui/transition/modal-transition.d.ts
vendored
Normal file
3
packages/core/ui/transition/modal-transition.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
import { Transition } from '.';
|
||||
|
||||
export declare class ModalTransition extends Transition {}
|
||||
292
packages/core/ui/transition/modal-transition.ios.ts
Normal file
292
packages/core/ui/transition/modal-transition.ios.ts
Normal file
@@ -0,0 +1,292 @@
|
||||
import { querySelectorAll } from '../core/view-base';
|
||||
import type { View } from '../core/view';
|
||||
import { Screen } from '../../platform';
|
||||
import { Transition } from '.';
|
||||
import type { TransitionType } from '.';
|
||||
import { SharedTransition, SharedTransitionAnimationType } from './shared-transition';
|
||||
|
||||
const printRect = (r: CGRect) => `CGRect(${r.origin.x} ${r.origin.y} ${r.size.width} ${r.size.height})`;
|
||||
const printPoint = (r: CGPoint) => `CGPoint(${r.x} ${r.y})`;
|
||||
const printSize = (r: CGSize) => `CGPoint(${r.width} ${r.height})`;
|
||||
|
||||
export class ModalTransition extends Transition implements TransitionType {
|
||||
transitionController: ModalTransitionController;
|
||||
presented: UIViewController;
|
||||
presenting: UIViewController;
|
||||
sharedElements: { presented?: Array<{ view: View; startFrame?: CGRect; endFrame?: CGRect; snapshot?: UIImageView }>; presenting?: Array<{ view: View; startFrame: CGRect; endFrame?: CGRect; snapshot?: UIImageView }> };
|
||||
|
||||
iosPresentedController(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIViewControllerAnimatedTransitioning {
|
||||
this.transitionController = ModalTransitionController.initWithOwner(new WeakRef(this));
|
||||
this.presented = presented;
|
||||
// console.log('presenting:', presenting)
|
||||
return this.transitionController;
|
||||
}
|
||||
|
||||
iosDismissedController(dismissed: UIViewController): UIViewControllerAnimatedTransitioning {
|
||||
this.transitionController = ModalTransitionController.initWithOwner(new WeakRef(this));
|
||||
this.presented = dismissed;
|
||||
return this.transitionController;
|
||||
}
|
||||
|
||||
iosInteractionDismiss(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
|
||||
console.log('-- iosInteractionDismiss --');
|
||||
return null;
|
||||
}
|
||||
|
||||
iosInteractionPresented(animator: UIViewControllerAnimatedTransitioning): UIViewControllerInteractiveTransitioning {
|
||||
console.log('-- iosInteractionPresented --');
|
||||
return null;
|
||||
}
|
||||
|
||||
iosPresentedViewController(presented: UIViewController, presenting: UIViewController, source: UIViewController): UIPresentationController {
|
||||
console.log('-- iosPresentedViewController --');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NativeClass()
|
||||
class ModalTransitionController extends NSObject implements UIViewControllerAnimatedTransitioning {
|
||||
static ObjCProtocols = [UIViewControllerAnimatedTransitioning];
|
||||
owner: WeakRef<ModalTransition>;
|
||||
|
||||
static initWithOwner(owner: WeakRef<ModalTransition>) {
|
||||
const ctrl = <ModalTransitionController>ModalTransitionController.new();
|
||||
ctrl.owner = owner;
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
transitionDuration(transitionContext: UIViewControllerContextTransitioning): number {
|
||||
return 0.35;
|
||||
}
|
||||
|
||||
animateTransition(transitionContext: UIViewControllerContextTransitioning): void {
|
||||
// console.log('FullScreenAnimationController animateTransition:', animationType);
|
||||
const owner = this.owner.deref();
|
||||
if (owner) {
|
||||
// console.log('owner.id:', owner.id);
|
||||
const state = SharedTransition.getState(owner.id);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
// console.log('state.activeType:', state.activeType)
|
||||
switch (state.activeType) {
|
||||
case SharedTransitionAnimationType.present:
|
||||
console.log('-- Transition present --');
|
||||
|
||||
transitionContext.containerView.addSubview(owner.presented.view);
|
||||
owner.presented.view.layoutIfNeeded();
|
||||
|
||||
// 1. Presented view: gather all sharedTransitionTag views
|
||||
const presentedSharedElements = <Array<View>>querySelectorAll(state.toPage, 'sharedTransitionTag');
|
||||
// console.log('presented sharedTransitionTag total:', presentedSharedElements.length);
|
||||
|
||||
// 2. Presenting view: gather all sharedTransitionTag views
|
||||
const presentingSharedElements = <Array<View>>querySelectorAll(state.page, 'sharedTransitionTag');
|
||||
// console.log('presenting sharedTransitionTag total:', presentingSharedElements.length);
|
||||
|
||||
// 3. only handle sharedTransitionTag on presenting which match presented
|
||||
const presentedTags = presentedSharedElements.map((v) => v.sharedTransitionTag);
|
||||
const presentingViewsToHandle = presentingSharedElements.filter((v) => presentedTags.includes(v.sharedTransitionTag));
|
||||
|
||||
console.log(' ');
|
||||
console.log(
|
||||
`1. Found sharedTransitionTags to animate:`,
|
||||
presentingViewsToHandle.map((v) => v.sharedTransitionTag)
|
||||
);
|
||||
|
||||
console.log(`2. Take snapshots of shared elements and position them based on presenting view:`);
|
||||
|
||||
for (const presentingView of presentingViewsToHandle) {
|
||||
if (!owner.sharedElements) {
|
||||
owner.sharedElements = {
|
||||
presented: [],
|
||||
presenting: [],
|
||||
};
|
||||
}
|
||||
const presentingSharedElement = presentingView.ios;
|
||||
// console.log('fromTarget instanceof UIImageView:', fromTarget instanceof UIImageView)
|
||||
|
||||
// TODO: discuss whether we should check if UIImage/UIImageView type to always snapshot images or if other view types could be duped/added vs. snapshotted
|
||||
// Note: snapshot may be most efficient/simple
|
||||
// console.log('---> ', presentingView.sharedTransitionTag, ': ', presentingSharedElement)
|
||||
|
||||
const sharedElementSnapshot = UIImageView.alloc().initWithImage(snapshotView(presentingSharedElement));
|
||||
sharedElementSnapshot.clipsToBounds = true;
|
||||
// console.log('---> snapshot: ', sharedElementSnapshot);
|
||||
|
||||
const presentedView = presentedSharedElements.find((v) => v.sharedTransitionTag === presentingView.sharedTransitionTag);
|
||||
const presentedSharedElement = presentedView.ios;
|
||||
|
||||
const startFrame = presentingSharedElement.convertRectToView(presentingSharedElement.bounds, transitionContext.containerView);
|
||||
const endFrame = presentedSharedElement.convertRectToView(presentedSharedElement.bounds, transitionContext.containerView);
|
||||
sharedElementSnapshot.frame = startFrame;
|
||||
console.log('---> ', presentingView.sharedTransitionTag, ' frame:', printRect(sharedElementSnapshot.frame));
|
||||
|
||||
owner.sharedElements.presenting.push({
|
||||
view: presentingView,
|
||||
startFrame,
|
||||
endFrame,
|
||||
snapshot: sharedElementSnapshot,
|
||||
});
|
||||
owner.sharedElements.presented.push({
|
||||
view: presentedView,
|
||||
startFrame: endFrame,
|
||||
endFrame: startFrame,
|
||||
});
|
||||
|
||||
// hide both while animating within the transition context
|
||||
presentingView.opacity = 0;
|
||||
presentedView.opacity = 0;
|
||||
// add snapshot to animate
|
||||
transitionContext.containerView.addSubview(sharedElementSnapshot);
|
||||
}
|
||||
|
||||
const cleanupPresent = () => {
|
||||
for (const presented of owner.sharedElements.presented) {
|
||||
presented.view.opacity = 1;
|
||||
}
|
||||
|
||||
// TODO: Discuss with Igor whether this is necessary
|
||||
// potential this could help smooth some shared element transitions
|
||||
UIView.animateWithDurationAnimationsCompletion(
|
||||
0.3,
|
||||
() => {
|
||||
for (const presenting of owner.sharedElements.presenting) {
|
||||
presenting.snapshot.alpha = 0;
|
||||
}
|
||||
},
|
||||
() => {
|
||||
for (const presenting of owner.sharedElements.presenting) {
|
||||
presenting.snapshot.removeFromSuperview();
|
||||
}
|
||||
SharedTransition.updateState({
|
||||
id: owner.id,
|
||||
activeType: SharedTransitionAnimationType.dismiss,
|
||||
});
|
||||
transitionContext.completeTransition(true);
|
||||
}
|
||||
);
|
||||
};
|
||||
const updateFramePresent = () => {
|
||||
// https://stackoverflow.com/a/27997678/1418981
|
||||
// In order to have proper layout. Seems mostly needed when presenting.
|
||||
// For instance during presentation, destination view doesn't account navigation bar height.
|
||||
// Not sure if best to leave all the time?
|
||||
// owner.presented.view.setNeedsLayout();
|
||||
// owner.presented.view.layoutIfNeeded();
|
||||
console.log('3. Animating shared elements:');
|
||||
for (const presented of owner.sharedElements.presented) {
|
||||
const presentingMatch = owner.sharedElements.presenting.find((v) => v.view.sharedTransitionTag === presented.view.sharedTransitionTag);
|
||||
// Workaround wrong origin due ongoing layout process.
|
||||
const updatedEndFrame = presented.view.ios.convertRectToView(presented.view.ios.bounds, transitionContext.containerView);
|
||||
const correctedEndFrame = CGRectMake(updatedEndFrame.origin.x, updatedEndFrame.origin.y, presentingMatch.endFrame.size.width, presentingMatch.endFrame.size.height);
|
||||
presentingMatch.snapshot.frame = correctedEndFrame;
|
||||
console.log(`---> ${presentingMatch.view.sharedTransitionTag} animate to: `, printRect(correctedEndFrame));
|
||||
}
|
||||
console.log(' ');
|
||||
};
|
||||
|
||||
// starting page properties
|
||||
owner.presented.view.alpha = typeof state.incomingViewStart?.opacity === 'number' ? state.incomingViewStart?.opacity : 0;
|
||||
|
||||
const startX = typeof state.incomingViewStart?.x === 'number' ? state.incomingViewStart?.x : 0;
|
||||
const startY = typeof state.incomingViewStart?.y === 'number' ? state.incomingViewStart?.y : Screen.mainScreen.heightDIPs;
|
||||
const startWidth = typeof state.incomingViewStart?.width === 'number' ? state.incomingViewStart?.width : Screen.mainScreen.widthDIPs;
|
||||
const startHeight = typeof state.incomingViewStart?.height === 'number' ? state.incomingViewStart?.height : Screen.mainScreen.heightDIPs;
|
||||
owner.presented.view.frame = CGRectMake(startX, startY, startWidth, startHeight);
|
||||
|
||||
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(
|
||||
typeof state.incomingViewStart?.duration === 'number' ? state.incomingViewStart?.duration / 1000 : 0.35,
|
||||
0,
|
||||
0.5,
|
||||
3,
|
||||
UIViewAnimationOptions.CurveEaseInOut,
|
||||
() => {
|
||||
// animate page properties to the following:
|
||||
owner.presented.view.alpha = typeof state.incomingViewEnd?.opacity === 'number' ? state.incomingViewEnd?.opacity : 1;
|
||||
|
||||
const endX = typeof state.incomingViewEnd?.x === 'number' ? state.incomingViewEnd?.x : 0;
|
||||
const endY = typeof state.incomingViewEnd?.y === 'number' ? state.incomingViewEnd?.y : 0;
|
||||
const endWidth = typeof state.incomingViewEnd?.width === 'number' ? state.incomingViewEnd?.width : Screen.mainScreen.widthDIPs;
|
||||
const endHeight = typeof state.incomingViewEnd?.height === 'number' ? state.incomingViewEnd?.height : Screen.mainScreen.heightDIPs;
|
||||
owner.presented.view.frame = CGRectMake(endX, endY, endWidth, endHeight);
|
||||
|
||||
updateFramePresent();
|
||||
},
|
||||
() => {
|
||||
cleanupPresent();
|
||||
}
|
||||
);
|
||||
break;
|
||||
case SharedTransitionAnimationType.dismiss:
|
||||
console.log('-- Transition dismiss --');
|
||||
|
||||
// console.log('transitionContext.containerView.subviews.count:', transitionContext.containerView.subviews.count);
|
||||
|
||||
console.log(' ');
|
||||
console.log(
|
||||
`1. Dismiss sharedTransitionTags to animate:`,
|
||||
owner.sharedElements.presented.map((p) => p.view.sharedTransitionTag)
|
||||
);
|
||||
|
||||
console.log(`2. Add back previously stored sharedElements to dismiss:`);
|
||||
|
||||
for (const p of owner.sharedElements.presented) {
|
||||
p.view.opacity = 0;
|
||||
}
|
||||
for (const p of owner.sharedElements.presenting) {
|
||||
p.snapshot.alpha = 1;
|
||||
transitionContext.containerView.addSubview(p.snapshot);
|
||||
}
|
||||
|
||||
const cleanupDismiss = () => {
|
||||
for (const presenting of owner.sharedElements.presenting) {
|
||||
presenting.view.opacity = 1;
|
||||
}
|
||||
SharedTransition.finishState(owner.id);
|
||||
transitionContext.completeTransition(true);
|
||||
};
|
||||
const updateFrameDismiss = () => {
|
||||
console.log('3. Dismissing shared elements:');
|
||||
for (const presenting of owner.sharedElements.presenting) {
|
||||
presenting.snapshot.frame = presenting.startFrame;
|
||||
console.log(`---> ${presenting.view.sharedTransitionTag} animate to: `, printRect(presenting.startFrame));
|
||||
}
|
||||
console.log(' ');
|
||||
};
|
||||
|
||||
UIView.animateWithDurationDelayUsingSpringWithDampingInitialSpringVelocityOptionsAnimationsCompletion(
|
||||
typeof state.dismissViewEnd?.duration === 'number' ? state.dismissViewEnd?.duration / 1000 : 0.35,
|
||||
0,
|
||||
0.5,
|
||||
3,
|
||||
UIViewAnimationOptions.CurveEaseInOut,
|
||||
() => {
|
||||
owner.presented.view.alpha = typeof state.dismissViewEnd?.opacity === 'number' ? state.dismissViewEnd?.opacity : 0;
|
||||
|
||||
const endX = typeof state.dismissViewEnd?.x === 'number' ? state.dismissViewEnd?.x : 0;
|
||||
const endY = typeof state.dismissViewEnd?.y === 'number' ? state.dismissViewEnd?.y : Screen.mainScreen.heightDIPs;
|
||||
const endWidth = typeof state.dismissViewEnd?.width === 'number' ? state.dismissViewEnd?.width : Screen.mainScreen.widthDIPs;
|
||||
const endHeight = typeof state.dismissViewEnd?.height === 'number' ? state.dismissViewEnd?.height : Screen.mainScreen.heightDIPs;
|
||||
owner.presented.view.frame = CGRectMake(endX, endY, endWidth, endHeight);
|
||||
|
||||
updateFrameDismiss();
|
||||
},
|
||||
() => {
|
||||
cleanupDismiss();
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function snapshotView(view: UIView): UIImage {
|
||||
// console.log('snapshotView view.frame:', printRect(view.frame));
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(view.frame.size.width, view.frame.size.height), false, Screen.mainScreen.scale);
|
||||
view.layer.renderInContext(UIGraphicsGetCurrentContext());
|
||||
const image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
94
packages/core/ui/transition/shared-transition.ts
Normal file
94
packages/core/ui/transition/shared-transition.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import type { Transition } from '.';
|
||||
// import type { View } from '../../core/view';
|
||||
import type { Page } from '../page';
|
||||
|
||||
// always increment when adding new transitions to be able to track their state
|
||||
export enum SharedTransitionAnimationType {
|
||||
present,
|
||||
dismiss,
|
||||
}
|
||||
export interface SharedTransitionConfig {
|
||||
/**
|
||||
* Page which will start the transition
|
||||
*/
|
||||
page?: Page;
|
||||
/**
|
||||
* Preconfigured transition or your own custom configured one
|
||||
*/
|
||||
instance?: Transition;
|
||||
/**
|
||||
* View settings to start your transition from.
|
||||
*/
|
||||
incomingViewStart?: SharedTransitionPageProperties;
|
||||
/**
|
||||
* View settings to animate your page to.
|
||||
*/
|
||||
incomingViewEnd?: SharedTransitionPageProperties;
|
||||
/**
|
||||
* View settings to animate your page to when dismissed.
|
||||
*/
|
||||
dismissViewEnd?: SharedTransitionPageProperties;
|
||||
}
|
||||
export interface SharedTransitionState extends SharedTransitionConfig {
|
||||
id?: number;
|
||||
activeType?: SharedTransitionAnimationType;
|
||||
toPage?: Page;
|
||||
}
|
||||
type SharedTransitionPageProperties = {
|
||||
x?: number;
|
||||
y?: number;
|
||||
width?: number;
|
||||
height?: number;
|
||||
opacity?: number;
|
||||
/**
|
||||
* Duration in milliseconds
|
||||
*/
|
||||
duration?: number;
|
||||
};
|
||||
export class SharedTransition {
|
||||
static configure(options: SharedTransitionConfig): Transition {
|
||||
SharedTransition.updateState({
|
||||
...options,
|
||||
id: options.instance.id,
|
||||
activeType: SharedTransitionAnimationType.present,
|
||||
});
|
||||
return options.instance;
|
||||
}
|
||||
|
||||
static currentStack: Array<SharedTransitionState>;
|
||||
static updateState(state: SharedTransitionState) {
|
||||
if (!SharedTransition.currentStack) {
|
||||
SharedTransition.currentStack = [];
|
||||
}
|
||||
const existingTransition = SharedTransition.getState(state.id);
|
||||
if (existingTransition) {
|
||||
// updating existing
|
||||
for (const key in state) {
|
||||
existingTransition[key] = state[key];
|
||||
// console.log(' ... updating state: ', key, state[key])
|
||||
}
|
||||
} else {
|
||||
SharedTransition.currentStack.push(state);
|
||||
}
|
||||
}
|
||||
static addPageToTop(page: Page) {
|
||||
if (SharedTransition.currentStack?.length) {
|
||||
const top = SharedTransition.currentStack.slice(-1)[0];
|
||||
if (top) {
|
||||
SharedTransition.updateState({
|
||||
id: top.id,
|
||||
toPage: page,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
static getState(id: number) {
|
||||
return SharedTransition.currentStack.find((t) => t.id === id);
|
||||
}
|
||||
static finishState(id: number) {
|
||||
const index = SharedTransition.currentStack.findIndex((t) => t.id === id);
|
||||
if (index > -1) {
|
||||
SharedTransition.currentStack.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user