mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
chore: improve android and other cleanups
This commit is contained in:
@@ -22,6 +22,7 @@ import { profile } from '../../profiling';
|
||||
import { setSuspended } from '../../application/application-common';
|
||||
import { ad } from '../../utils/native-helper';
|
||||
import type { ExpandedEntry } from './fragment.transitions.android';
|
||||
import { SharedTransition, SharedTransitionAnimationType } from '../transition/shared-transition';
|
||||
|
||||
export * from './frame-common';
|
||||
|
||||
@@ -467,6 +468,12 @@ export class Frame extends FrameBase {
|
||||
navigationTransition?.instance?.androidFragmentTransactionCallback?.(transaction, currentEntry, newEntry);
|
||||
|
||||
transaction.commitAllowingStateLoss();
|
||||
|
||||
if (navigationTransition?.instance) {
|
||||
SharedTransition.updateState(navigationTransition?.instance?.id, {
|
||||
activeType: SharedTransitionAnimationType.dismiss,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public _goBackCore(backstackEntry: BackstackEntry & ExpandedEntry) {
|
||||
@@ -492,6 +499,10 @@ export class Frame extends FrameBase {
|
||||
backstackEntry.transition?.androidFragmentTransactionCallback?.(transaction, this._currentEntry, backstackEntry);
|
||||
|
||||
transaction.commitAllowingStateLoss();
|
||||
|
||||
if (backstackEntry?.transition) {
|
||||
SharedTransition.finishState(backstackEntry.transition.id);
|
||||
}
|
||||
}
|
||||
|
||||
public _removeEntry(removed: BackstackEntry): void {
|
||||
|
||||
@@ -27,6 +27,10 @@ export class Transition implements TransitionType {
|
||||
return this._duration;
|
||||
}
|
||||
|
||||
public setDuration(value: number) {
|
||||
this._duration = value;
|
||||
}
|
||||
|
||||
public getCurve(): android.view.animation.Interpolator {
|
||||
return this._interpolator;
|
||||
}
|
||||
|
||||
1
packages/core/ui/transition/index.d.ts
vendored
1
packages/core/ui/transition/index.d.ts
vendored
@@ -24,6 +24,7 @@ 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 */);
|
||||
getDuration(): number;
|
||||
setDuration(value: number): void;
|
||||
getCurve(): any;
|
||||
animateIOSTransition(transitionContext: any /*UIViewControllerContextTransitioning */, fromViewCtrl: any /* UIViewController */, toViewCtrl: any /* UIViewController */, operation: any /* UINavigationControllerOperation */): void;
|
||||
createAndroidAnimator(transitionType: string): any;
|
||||
|
||||
@@ -1,14 +1,57 @@
|
||||
import type { View } from '../core/view';
|
||||
import { ViewBase } from '../core/view-base';
|
||||
import { BackstackEntry } from '../frame';
|
||||
import { isNumber } from '../../utils/types';
|
||||
import { FadeTransition } from './fade-transition';
|
||||
import { SharedTransition } from './shared-transition';
|
||||
import { SharedTransition, SharedTransitionAnimationType } from './shared-transition';
|
||||
import { ImageSource } from '../../image-source';
|
||||
import { ContentView } from '../content-view';
|
||||
import { GridLayout } from '../layouts/grid-layout';
|
||||
import { ad } from '../../utils';
|
||||
// import { Image } from '../image';
|
||||
|
||||
@NativeClass
|
||||
class CustomInterpolator extends android.view.animation.AnticipateOvershootInterpolator {
|
||||
class SnapshotViewGroup extends android.view.ViewGroup {
|
||||
constructor(context: android.content.Context) {
|
||||
super(context);
|
||||
return global.__native(this);
|
||||
}
|
||||
public onMeasure(): void {
|
||||
this.setMeasuredDimension(0, 0);
|
||||
}
|
||||
public onLayout(): void {
|
||||
//
|
||||
}
|
||||
}
|
||||
class ContentViewSnapshot extends ContentView {
|
||||
createNativeView() {
|
||||
return new SnapshotViewGroup(this._context);
|
||||
}
|
||||
}
|
||||
|
||||
@NativeClass
|
||||
class CustomSpringInterpolator extends android.view.animation.AnticipateOvershootInterpolator {
|
||||
getInterpolation(input: number) {
|
||||
// HACK: we speed up the interpolation by 10% to fix the issue with the transition not being finished
|
||||
// Note: we speed up the interpolation by 10% to fix the issue with the transition not being finished
|
||||
// and the views shifting from their intended final position...
|
||||
// this is really just a hack and should be fixed properly once we
|
||||
// this is really just a workaround and should be fixed properly once we
|
||||
// can figure out the root cause of the issue.
|
||||
const res = super.getInterpolation(input) * 1.1;
|
||||
|
||||
if (res > 1) {
|
||||
return float(1);
|
||||
}
|
||||
|
||||
return float(res);
|
||||
}
|
||||
}
|
||||
|
||||
@NativeClass
|
||||
class CustomLinearInterpolator extends android.view.animation.LinearInterpolator {
|
||||
getInterpolation(input: number) {
|
||||
// Note: we speed up the interpolation by 10% to fix the issue with the transition not being finished
|
||||
// and the views shifting from their intended final position...
|
||||
// this is really just a workaround and should be fixed properly once we
|
||||
// can figure out the root cause of the issue.
|
||||
const res = super.getInterpolation(input) * 1.1;
|
||||
|
||||
@@ -21,7 +64,7 @@ class CustomInterpolator extends android.view.animation.AnticipateOvershootInter
|
||||
}
|
||||
|
||||
function setTransitionName(view: ViewBase) {
|
||||
if (!view.sharedTransitionTag) {
|
||||
if (!view?.sharedTransitionTag) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@@ -44,26 +87,77 @@ export class PageTransition extends FadeTransition {
|
||||
const fromPage = currentEntry.resolvedPage;
|
||||
const toPage = newEntry.resolvedPage;
|
||||
const newFragment: androidx.fragment.app.Fragment = newEntry.fragment;
|
||||
const state = SharedTransition.getState(this.id);
|
||||
const pageEnd = state.pageEnd;
|
||||
|
||||
const { presented, presenting } = SharedTransition.getSharedElements(fromPage, toPage);
|
||||
const { sharedElements, presented, presenting } = SharedTransition.getSharedElements(fromPage, toPage);
|
||||
const sharedElementTags = sharedElements.map((v) => v.sharedTransitionTag);
|
||||
if (SharedTransition.DEBUG) {
|
||||
console.log(` Page: ${state.activeType === SharedTransitionAnimationType.present ? 'Present' : 'Dismiss'}`);
|
||||
console.log(`1. Found sharedTransitionTags to animate:`, sharedElementTags);
|
||||
}
|
||||
|
||||
// Note: we can enhance android more over time with element targeting across different screens
|
||||
// const pageStart = state.pageStart;
|
||||
// const pageEndIndependentTags = Object.keys(pageEnd?.sharedTransitionTags || {});
|
||||
// console.log('pageEndIndependentTags:', pageEndIndependentTags);
|
||||
// for (const tag of pageEndIndependentTags) {
|
||||
// // only consider start when there's a matching end
|
||||
// const pageStartIndependentProps = pageStart?.sharedTransitionTags[tag];
|
||||
// if (pageStartIndependentProps) {
|
||||
// console.log('pageStartIndependentProps:', tag, pageStartIndependentProps);
|
||||
// }
|
||||
// const pageEndIndependentProps = pageEnd?.sharedTransitionTags[tag];
|
||||
// let independentView = presenting.find((v) => v.sharedTransitionTag === tag);
|
||||
// let isPresented = false;
|
||||
// if (!independentView) {
|
||||
// independentView = presented.find((v) => v.sharedTransitionTag === tag);
|
||||
// if (!independentView) {
|
||||
// break;
|
||||
// }
|
||||
// isPresented = true;
|
||||
// }
|
||||
// if (independentView) {
|
||||
// console.log('independentView:', independentView);
|
||||
// const imageSource = renderToImageSource(independentView);
|
||||
// const image = new Image();
|
||||
// image.src = imageSource;
|
||||
// const { hostView } = loadViewInBackground(image);
|
||||
// (<any>fromPage).addChild(hostView);
|
||||
// independentView.opacity = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
toPage.once('loaded', () => {
|
||||
presented.forEach(setTransitionName);
|
||||
presented.filter((v) => sharedElementTags.includes(v.sharedTransitionTag)).forEach(setTransitionName);
|
||||
newFragment.startPostponedEnterTransition();
|
||||
});
|
||||
|
||||
presenting.forEach((v) => {
|
||||
sharedElements.forEach((v) => {
|
||||
setTransitionName(v);
|
||||
fragmentTransaction.addSharedElement(v.nativeView, v.sharedTransitionTag);
|
||||
});
|
||||
|
||||
fragmentTransaction.setReorderingAllowed(true);
|
||||
|
||||
let customDuration = -1;
|
||||
if (state.activeType === SharedTransitionAnimationType.present && isNumber(pageEnd?.duration)) {
|
||||
customDuration = pageEnd.duration;
|
||||
} else if (isNumber(state.pageReturn?.duration)) {
|
||||
customDuration = state.pageReturn.duration;
|
||||
}
|
||||
|
||||
const transitionSet = new androidx.transition.TransitionSet();
|
||||
transitionSet.setDuration(this.getDuration());
|
||||
transitionSet.setDuration(customDuration || this.getDuration());
|
||||
transitionSet.addTransition(new androidx.transition.ChangeBounds());
|
||||
transitionSet.addTransition(new androidx.transition.ChangeTransform());
|
||||
transitionSet.setInterpolator(new CustomInterpolator());
|
||||
|
||||
if (customDuration) {
|
||||
// duration always overrides default spring
|
||||
transitionSet.setInterpolator(new CustomLinearInterpolator());
|
||||
} else {
|
||||
transitionSet.setInterpolator(new CustomSpringInterpolator());
|
||||
}
|
||||
|
||||
// postpone enter until we call "loaded" on the new page
|
||||
newFragment.postponeEnterTransition();
|
||||
@@ -71,3 +165,29 @@ export class PageTransition extends FadeTransition {
|
||||
newFragment.setSharedElementReturnTransition(transitionSet);
|
||||
}
|
||||
}
|
||||
|
||||
function renderToImageSource(hostView: View): ImageSource {
|
||||
const bitmap = android.graphics.Bitmap.createBitmap(hostView.android.getWidth(), hostView.android.getHeight(), android.graphics.Bitmap.Config.ARGB_8888);
|
||||
const canvas = new android.graphics.Canvas(bitmap);
|
||||
// ensure we start with a blank transparent canvas
|
||||
canvas.drawARGB(0, 0, 0, 0);
|
||||
hostView.android.draw(canvas);
|
||||
return new ImageSource(bitmap);
|
||||
}
|
||||
|
||||
function loadViewInBackground(view: View) {
|
||||
const hiddenHost = new ContentViewSnapshot();
|
||||
const hostView = new GridLayout(); // use a host view to ensure margins are respected
|
||||
hiddenHost.content = hostView;
|
||||
hiddenHost.visibility = 'collapse';
|
||||
hostView.addChild(view);
|
||||
hiddenHost._setupAsRootView(ad.getApplicationContext());
|
||||
hiddenHost.callLoaded();
|
||||
|
||||
ad.getCurrentActivity().addContentView(hiddenHost.android, new android.view.ViewGroup.LayoutParams(0, 0));
|
||||
|
||||
return {
|
||||
hiddenHost,
|
||||
hostView,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import type { View } from '../core/view';
|
||||
import { SharedElementSettings, SharedInteractiveState, Transition } from '.';
|
||||
import { Screen } from '../../platform';
|
||||
import { iOSNativeHelper } from '../../utils/native-helper';
|
||||
import { isNumber } from '../../utils/types';
|
||||
import { PanGestureEventData, GestureStateTypes } from '../gestures';
|
||||
import { SharedTransition, SharedTransitionAnimationType, DEFAULT_DURATION, DEFAULT_SPRING, getRectFromProps, getPageStartDefaultsForType } from './shared-transition';
|
||||
import { SharedTransition, DEFAULT_DURATION } from './shared-transition';
|
||||
import { SharedTransitionHelper } from './shared-transition-helper';
|
||||
|
||||
export class PageTransition extends Transition {
|
||||
|
||||
@@ -89,6 +89,10 @@ type SharedTransitionPageProperties = SharedProperties & {
|
||||
* Note: When this is defined, it will override spring options and use only linear animation.
|
||||
*/
|
||||
duration?: number;
|
||||
/**
|
||||
* (iOS Only) Allow "independent" elements found only on one of the screens to take part in the animation.
|
||||
* Note: This feature will be brought to Android in a future release.
|
||||
*/
|
||||
sharedTransitionTags?: { [key: string]: SharedProperties };
|
||||
/**
|
||||
* Spring animation settings.
|
||||
@@ -116,6 +120,10 @@ export class SharedTransition {
|
||||
instance: transition,
|
||||
activeType: SharedTransitionAnimationType.present,
|
||||
});
|
||||
const pageEnd = options.pageEnd;
|
||||
if (isNumber(pageEnd?.duration)) {
|
||||
transition.setDuration(pageEnd?.duration);
|
||||
}
|
||||
return { instance: transition };
|
||||
}
|
||||
static events() {
|
||||
|
||||
Reference in New Issue
Block a user