fix(hmr): quick fade upon replace navigation (#7251)

This commit is contained in:
Manol Donev
2019-05-22 11:45:55 +03:00
committed by GitHub
parent d60e5dace4
commit 0aca08755a
6 changed files with 58 additions and 20 deletions

View File

@ -146,9 +146,5 @@ function _test_onLiveSync_ModuleContext_TypeStyle(context: { type, path }) {
} }
function waitUntilLivesyncComplete(frame: Frame) { function waitUntilLivesyncComplete(frame: Frame) {
if (isAndroid) { TKUnit.waitUntilReady(() => frame._executingEntry === null);
TKUnit.waitUntilReady(() => frame._executingEntry === null);
} else {
TKUnit.waitUntilReady(() => frame.currentPage.isLoaded);
}
} }

View File

@ -5,7 +5,7 @@ import {
} from "."; } from ".";
import { import {
ViewBase, Property, booleanConverter, eachDescendant, EventData, layout, ViewBase, Property, booleanConverter, EventData, layout,
getEventOrGestureName, traceEnabled, traceWrite, traceCategories, getEventOrGestureName, traceEnabled, traceWrite, traceCategories,
InheritedProperty, ShowModalOptions InheritedProperty, ShowModalOptions
} from "../view-base"; } from "../view-base";

View File

@ -169,8 +169,11 @@ export function _setAndroidFragmentTransitions(
// Having transition means we have custom animation // Having transition means we have custom animation
if (transition) { if (transition) {
// we do not use Android backstack so setting popEnter / popExit is meaningless (3rd and 4th optional args) if (fragmentTransaction) {
fragmentTransaction.setCustomAnimations(AnimationType.enterFakeResourceId, AnimationType.exitFakeResourceId); // we do not use Android backstack so setting popEnter / popExit is meaningless (3rd and 4th optional args)
fragmentTransaction.setCustomAnimations(AnimationType.enterFakeResourceId, AnimationType.exitFakeResourceId);
}
setupAllAnimation(newEntry, transition); setupAllAnimation(newEntry, transition);
if (currentFragmentNeedsDifferentAnimation) { if (currentFragmentNeedsDifferentAnimation) {
setupExitAndPopEnterAnimation(currentEntry, transition); setupExitAndPopEnterAnimation(currentEntry, transition);
@ -502,6 +505,8 @@ function clearEntry(entry: ExpandedEntry, removeListener: boolean): void {
clearAnimationListener(entry.exitAnimator, listener); clearAnimationListener(entry.exitAnimator, listener);
clearAnimationListener(entry.popEnterAnimator, listener); clearAnimationListener(entry.popEnterAnimator, listener);
clearAnimationListener(entry.popExitAnimator, listener); clearAnimationListener(entry.popExitAnimator, listener);
clearAnimationListener(entry.defaultEnterAnimator, listener);
clearAnimationListener(entry.defaultExitAnimator, listener);
} }
} }

View File

@ -1,14 +1,14 @@
// Definitions. // Definitions.
import { import {
AndroidFrame as AndroidFrameDefinition, AndroidActivityCallbacks, AndroidFrame as AndroidFrameDefinition, AndroidActivityCallbacks,
AndroidFragmentCallbacks, BackstackEntry, NavigationTransition AndroidFragmentCallbacks, BackstackEntry, NavigationTransition, NavigationEntry
} from "."; } from ".";
import { Page } from "../page"; import { Page } from "../page";
// Types. // Types.
import * as application from "../../application"; import * as application from "../../application";
import { import {
FrameBase, goBack, stack, NavigationContext, NavigationType, FrameBase, goBack, stack, NavigationType,
Observable, View, traceCategories, traceEnabled, traceError, traceWrite Observable, View, traceCategories, traceEnabled, traceError, traceWrite
} from "./frame-common"; } from "./frame-common";
@ -21,7 +21,6 @@ import { profile } from "../../profiling";
// TODO: Remove this and get it from global to decouple builder for angular // TODO: Remove this and get it from global to decouple builder for angular
import { createViewFromEntry } from "../builder"; import { createViewFromEntry } from "../builder";
import { getModuleName } from "../../utils/utils";
export * from "./frame-common"; export * from "./frame-common";
@ -37,6 +36,7 @@ const INTENT_EXTRA = "com.tns.activity";
const ROOT_VIEW_ID_EXTRA = "com.tns.activity.rootViewId"; const ROOT_VIEW_ID_EXTRA = "com.tns.activity.rootViewId";
const FRAMEID = "_frameId"; const FRAMEID = "_frameId";
const CALLBACKS = "_callbacks"; const CALLBACKS = "_callbacks";
const HMR_REPLACE_TRANSITION = "fade";
const ownerSymbol = Symbol("_owner"); const ownerSymbol = Symbol("_owner");
const activityRootViewsMap = new Map<number, WeakRef<View>>(); const activityRootViewsMap = new Map<number, WeakRef<View>>();
@ -319,6 +319,18 @@ export class Frame extends FrameBase {
restoreAnimatorState(this._currentEntry, this._cachedAnimatorState); restoreAnimatorState(this._currentEntry, this._cachedAnimatorState);
this._cachedAnimatorState = null; this._cachedAnimatorState = null;
} }
// restore original fragment transitions if we just completed replace navigation (hmr)
if (navigationType === NavigationType.replace) {
_clearEntry(entry);
const animated = entry.entry.animated;
const navigationTransition = this._getNavigationTransition(entry.entry);
const currentEntry = null;
const newEntry = entry;
const transaction = null;
_setAndroidFragmentTransitions(animated, navigationTransition, currentEntry, newEntry, transaction, this._android.frameId);
}
} }
public onBackPressed(): boolean { public onBackPressed(): boolean {
@ -381,12 +393,20 @@ export class Frame extends FrameBase {
const newFragmentTag = `fragment${fragmentId}[${navDepth}]`; const newFragmentTag = `fragment${fragmentId}[${navDepth}]`;
const newFragment = this.createFragment(newEntry, newFragmentTag); const newFragment = this.createFragment(newEntry, newFragmentTag);
const transaction = manager.beginTransaction(); const transaction = manager.beginTransaction();
const animated = currentEntry ? this._getIsAnimatedNavigation(newEntry.entry) : false; let animated = currentEntry ? this._getIsAnimatedNavigation(newEntry.entry) : false;
// NOTE: Don't use transition for the initial navigation (same as on iOS) // NOTE: Don't use transition for the initial navigation (same as on iOS)
// On API 21+ transition won't be triggered unless there was at least one // On API 21+ transition won't be triggered unless there was at least one
// layout pass so we will wait forever for transitionCompleted handler... // layout pass so we will wait forever for transitionCompleted handler...
// https://github.com/NativeScript/NativeScript/issues/4895 // https://github.com/NativeScript/NativeScript/issues/4895
const navigationTransition = this._currentEntry ? this._getNavigationTransition(newEntry.entry) : null; let navigationTransition: NavigationTransition;
if (isReplace) {
animated = true;
navigationTransition = { name: HMR_REPLACE_TRANSITION, duration: 100 };
} else if (this._currentEntry) {
navigationTransition = this._getNavigationTransition(newEntry.entry);
} else {
navigationTransition = null;
}
_setAndroidFragmentTransitions(animated, navigationTransition, currentEntry, newEntry, transaction, this._android.frameId); _setAndroidFragmentTransitions(animated, navigationTransition, currentEntry, newEntry, transaction, this._android.frameId);

View File

@ -7,12 +7,11 @@ import { profile } from "../../profiling";
//Types. //Types.
import { import {
FrameBase, View, isCategorySet, layout, NavigationContext, FrameBase, View, isCategorySet, layout,
NavigationType, traceCategories, traceEnabled, traceWrite NavigationType, traceCategories, traceEnabled, traceWrite
} from "./frame-common"; } from "./frame-common";
import { _createIOSAnimatedTransitioning } from "./fragment.transitions"; import { _createIOSAnimatedTransitioning } from "./fragment.transitions";
import { createViewFromEntry } from "../builder";
import * as utils from "../../utils/utils"; import * as utils from "../../utils/utils";
export * from "./frame-common"; export * from "./frame-common";
@ -24,6 +23,7 @@ const DELEGATE = "_delegate";
const NAV_DEPTH = "_navDepth"; const NAV_DEPTH = "_navDepth";
const TRANSITION = "_transition"; const TRANSITION = "_transition";
const NON_ANIMATED_TRANSITION = "non-animated"; const NON_ANIMATED_TRANSITION = "non-animated";
const HMR_REPLACE_TRANSITION = "fade";
let navDepth = -1; let navDepth = -1;
@ -88,13 +88,16 @@ export class Frame extends FrameBase {
let navigationTransition: NavigationTransition; let navigationTransition: NavigationTransition;
let animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false; let animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false;
if (animated) { if (isReplace) {
animated = true;
navigationTransition = { name: HMR_REPLACE_TRANSITION, duration: 100 }
viewController[TRANSITION] = navigationTransition;
} else if (animated) {
navigationTransition = this._getNavigationTransition(backstackEntry.entry); navigationTransition = this._getNavigationTransition(backstackEntry.entry);
if (navigationTransition) { if (navigationTransition) {
viewController[TRANSITION] = navigationTransition; viewController[TRANSITION] = navigationTransition;
} }
} } else {
else {
//https://github.com/NativeScript/NativeScript/issues/1787 //https://github.com/NativeScript/NativeScript/issues/1787
viewController[TRANSITION] = { name: NON_ANIMATED_TRANSITION }; viewController[TRANSITION] = { name: NON_ANIMATED_TRANSITION };
} }

View File

@ -1,5 +1,5 @@
// Definitions. // Definitions.
import { Frame } from "../frame"; import { Frame, BackstackEntry } from "../frame";
import { NavigationType } from "../frame/frame-common"; import { NavigationType } from "../frame/frame-common";
// Types. // Types.
@ -15,6 +15,8 @@ export * from "./page-common";
const ENTRY = "_entry"; const ENTRY = "_entry";
const DELEGATE = "_delegate"; const DELEGATE = "_delegate";
const TRANSITION = "_transition";
const NON_ANIMATED_TRANSITION = "non-animated";
const majorVersion = iosUtils.MajorVersion; const majorVersion = iosUtils.MajorVersion;
@ -130,7 +132,7 @@ class UIViewControllerImpl extends UIViewController {
const frame = navigationController ? (<any>navigationController).owner : null; const frame = navigationController ? (<any>navigationController).owner : null;
// Skip navigation events if modal page is shown. // Skip navigation events if modal page is shown.
if (!owner._presentedViewController && frame) { if (!owner._presentedViewController && frame) {
const newEntry = this[ENTRY]; const newEntry: BackstackEntry = this[ENTRY];
let isBack: boolean; let isBack: boolean;
let navType = frame.navigationType; let navType = frame.navigationType;
@ -146,6 +148,18 @@ class UIViewControllerImpl extends UIViewController {
} }
frame.setCurrent(newEntry, navType); frame.setCurrent(newEntry, navType);
if (frame.navigationType === NavigationType.replace) {
let controller = newEntry.resolvedPage.ios;
if (controller) {
if (newEntry.entry.animated) {
controller[TRANSITION] = frame._getNavigationTransition(newEntry.entry);
} else {
controller[TRANSITION] = { name: NON_ANIMATED_TRANSITION };
}
}
}
frame.navigationType = isBack ? NavigationType.back : NavigationType.forward; frame.navigationType = isBack ? NavigationType.back : NavigationType.forward;
// If page was shown with custom animation - we need to set the navigationController.delegate to the animatedDelegate. // If page was shown with custom animation - we need to set the navigationController.delegate to the animatedDelegate.