Fix swipe-back in iOS

This commit is contained in:
Hristo Hristov
2016-03-25 12:01:02 +02:00
parent e0f52b1031
commit 429646f392
12 changed files with 201 additions and 169 deletions

View File

@ -768,6 +768,8 @@
<TypeScriptCompile Include="ui\text-base\text-base-styler.ios.ts" /> <TypeScriptCompile Include="ui\text-base\text-base-styler.ios.ts" />
<TypeScriptCompile Include="ui\transition\flip-transition.android.ts" /> <TypeScriptCompile Include="ui\transition\flip-transition.android.ts" />
<TypeScriptCompile Include="ui\transition\fade-transition.android.ts" /> <TypeScriptCompile Include="ui\transition\fade-transition.android.ts" />
<TypeScriptCompile Include="ui\transition\fade-transition.d.ts" />
<TypeScriptCompile Include="ui\transition\slide-transition.d.ts" />
<TypeScriptCompile Include="ui\transition\slide-transition.ios.ts" /> <TypeScriptCompile Include="ui\transition\slide-transition.ios.ts" />
<TypeScriptCompile Include="ui\transition\slide-transition.android.ts" /> <TypeScriptCompile Include="ui\transition\slide-transition.android.ts" />
<TypeScriptCompile Include="ui\transition\fade-transition.ios.ts" /> <TypeScriptCompile Include="ui\transition\fade-transition.ios.ts" />
@ -2201,7 +2203,7 @@
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties> </WebProjectProperties>
</FlavorProperties> </FlavorProperties>
<UserProperties ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" /> <UserProperties ui_2scroll-view_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2editable-text-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2absolute-layout-demo_2package_1json__JSONSchema="http://json.schemastore.org/package" apps_2gallery-app_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2content-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2web-view_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2absolute-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" ui_2layouts_2dock-layout_2package_1json__JSONSchema="" ui_2layouts_2grid-layout_2package_1json__JSONSchema="" ui_2layouts_2wrap-layout_2package_1json__JSONSchema="http://json.schemastore.org/package" />
</VisualStudio> </VisualStudio>
</ProjectExtensions> </ProjectExtensions>
</Project> </Project>

4
ios.d.ts vendored
View File

@ -20624,8 +20624,8 @@ interface UIViewControllerContextTransitioning {
finalFrameForViewController(vc: UIViewController): CGRect; finalFrameForViewController(vc: UIViewController): CGRect;
} }
interface UIViewControllerAnimatedTransitioning { interface UIViewControllerAnimatedTransitioning {
transitionDuration(transitionContext: any): number; transitionDuration(transitionContext: UIViewControllerContextTransitioning): number;
animateTransition(transitionContext: any): void; animateTransition(transitionContext: UIViewControllerContextTransitioning): void;
animationEnded?(transitionCompleted: boolean): void; animationEnded?(transitionCompleted: boolean): void;
} }
interface UIViewControllerInteractiveTransitioning { interface UIViewControllerInteractiveTransitioning {

6
trace/trace.d.ts vendored
View File

@ -41,6 +41,12 @@ declare module "trace" {
*/ */
export function addCategories(categories: string); export function addCategories(categories: string);
/**
* Check if category is already set in trace module.
* @param category The category to check.
*/
export function isCategorySet(category: string): boolean;
/** /**
* Writes a message using the available writers. * Writes a message using the available writers.
* @param message The message to be written. * @param message The message to be written.

View File

@ -14,6 +14,10 @@ export function disable() {
_enabled = false; _enabled = false;
} }
export function isCategorySet(category: string): boolean {
return category in _categories;
}
export function addWriter(writer: definition.TraceWriter) { export function addWriter(writer: definition.TraceWriter) {
_writers.push(writer); _writers.push(writer);
} }

View File

@ -688,6 +688,8 @@
"ui/transition/transition.android.ts", "ui/transition/transition.android.ts",
"ui/transition/transition.d.ts", "ui/transition/transition.d.ts",
"ui/transition/transition.ios.ts", "ui/transition/transition.ios.ts",
"ui/transition/fade-transition.d.ts",
"ui/transition/slide-transition.d.ts",
"ui/utils.d.ts", "ui/utils.d.ts",
"ui/utils.ios.ts", "ui/utils.ios.ts",
"ui/web-view/web-view-common.ts", "ui/web-view/web-view-common.ts",

View File

@ -402,7 +402,7 @@ export class Frame extends CustomLayoutView implements definition.Frame {
return entry.transitionAndroid; return entry.transitionAndroid;
} }
if (entry && isDefined(entry.transition)) { if (isDefined(entry.transition)) {
return entry.transition; return entry.transition;
} }
} }

View File

@ -1,25 +1,29 @@
import frameCommon = require("./frame-common"); import frameCommon = require("./frame-common");
import definition = require("ui/frame"); import definition = require("ui/frame");
import trace = require("trace"); import trace = require("trace");
import pages = require("ui/page"); import {Page} from "ui/page";
import enums = require("ui/enums"); import {NavigationBarVisibility, AnimationCurve} from "ui/enums";
import utils = require("utils/utils"); import utils = require("utils/utils");
import view = require("ui/core/view"); import {View} from "ui/core/view";
import uiUtils = require("ui/utils"); import uiUtils = require("ui/utils");
import * as types from "utils/types"; import * as types from "utils/types";
import * as transitionModule from "ui/transition";
import application = require("application"); import application = require("application");
import * as _transitionModule from "ui/transition";
var transitionModule: typeof _transitionModule;
global.moduleMerge(frameCommon, exports); global.moduleMerge(frameCommon, exports);
var ENTRY = "_entry"; var ENTRY = "_entry";
var NAV_DEPTH = "_navDepth"; var NAV_DEPTH = "_navDepth";
var TRANSITION = "_transition"; var TRANSITION = "_transition";
var DELEGATE = "_delegate";
var navDepth = -1; var navDepth = -1;
export class Frame extends frameCommon.Frame { export class Frame extends frameCommon.Frame {
private _ios: iOSFrame; private _ios: iOSFrame;
private _paramToNavigate: any; private _paramToNavigate: any;
public _animatedDelegate = <UINavigationControllerDelegate>UINavigationControllerAnimatedDelegate.new();
public _shouldSkipNativePop: boolean = false; public _shouldSkipNativePop: boolean = false;
public _navigateToEntry: definition.BackstackEntry; public _navigateToEntry: definition.BackstackEntry;
@ -65,16 +69,17 @@ export class Frame extends frameCommon.Frame {
public _navigateCore(backstackEntry: definition.BackstackEntry) { public _navigateCore(backstackEntry: definition.BackstackEntry) {
trace.write(`${this}._navigateCore(page: ${backstackEntry.resolvedPage}, backstackVisible: ${this._isEntryBackstackVisible(backstackEntry)}, clearHistory: ${backstackEntry.entry.clearHistory}), navDepth: ${navDepth}`, trace.categories.Navigation); trace.write(`${this}._navigateCore(page: ${backstackEntry.resolvedPage}, backstackVisible: ${this._isEntryBackstackVisible(backstackEntry)}, clearHistory: ${backstackEntry.entry.clearHistory}), navDepth: ${navDepth}`, trace.categories.Navigation);
var viewController: UIViewController = backstackEntry.resolvedPage.ios; let viewController: UIViewController = backstackEntry.resolvedPage.ios;
if (!viewController) { if (!viewController) {
throw new Error("Required page does not have a viewController created."); throw new Error("Required page does not have a viewController created.");
} }
navDepth++; navDepth++;
var animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false; let navigationTransition: definition.NavigationTransition;
let animated = this.currentPage ? this._getIsAnimatedNavigation(backstackEntry.entry) : false;
if (animated) { if (animated) {
var navigationTransition = this._getNavigationTransition(backstackEntry.entry); navigationTransition = this._getNavigationTransition(backstackEntry.entry);
if (navigationTransition) { if (navigationTransition) {
viewController[TRANSITION] = navigationTransition; viewController[TRANSITION] = navigationTransition;
} }
@ -84,6 +89,16 @@ export class Frame extends frameCommon.Frame {
viewController[TRANSITION] = { name: "non-animated" }; viewController[TRANSITION] = { name: "non-animated" };
} }
let nativeTransition = _getNativeTransition(navigationTransition, true);
if (!nativeTransition && navigationTransition) {
this._ios.controller.delegate = this._animatedDelegate;
viewController[DELEGATE] = this._animatedDelegate;
}
else {
viewController[DELEGATE] = null;
this._ios.controller.delegate = null;
}
backstackEntry[NAV_DEPTH] = navDepth; backstackEntry[NAV_DEPTH] = navDepth;
viewController[ENTRY] = backstackEntry; viewController[ENTRY] = backstackEntry;
@ -147,7 +162,7 @@ export class Frame extends frameCommon.Frame {
} }
} }
public _updateActionBar(page?: pages.Page): void { public _updateActionBar(page?: Page): void {
super._updateActionBar(page); super._updateActionBar(page);
var page = page || this.currentPage; var page = page || this.currentPage;
@ -159,15 +174,15 @@ export class Frame extends frameCommon.Frame {
} }
} }
public _getNavBarVisible(page: pages.Page): boolean { public _getNavBarVisible(page: Page): boolean {
switch (this._ios.navBarVisibility) { switch (this._ios.navBarVisibility) {
case enums.NavigationBarVisibility.always: case NavigationBarVisibility.always:
return true; return true;
case enums.NavigationBarVisibility.never: case NavigationBarVisibility.never:
return false; return false;
case enums.NavigationBarVisibility.auto: case NavigationBarVisibility.auto:
let newValue: boolean; let newValue: boolean;
if (page && types.isDefined(page.actionBarHidden)) { if (page && types.isDefined(page.actionBarHidden)) {
@ -230,13 +245,14 @@ export class Frame extends frameCommon.Frame {
result.measuredWidth = Math.max(result.measuredWidth, newPageSize.measuredWidth); result.measuredWidth = Math.max(result.measuredWidth, newPageSize.measuredWidth);
result.measuredHeight = Math.max(result.measuredHeight, newPageSize.measuredHeight); result.measuredHeight = Math.max(result.measuredHeight, newPageSize.measuredHeight);
} }
let widthAndState = view.View.resolveSizeAndState(result.measuredWidth, width, widthMode, 0);
let heightAndState = view.View.resolveSizeAndState(result.measuredHeight, height, heightMode, 0); let widthAndState = View.resolveSizeAndState(result.measuredWidth, width, widthMode, 0);
let heightAndState = View.resolveSizeAndState(result.measuredHeight, height, heightMode, 0);
this.setMeasuredDimension(widthAndState, heightAndState); this.setMeasuredDimension(widthAndState, heightAndState);
} }
public measurePage(page: pages.Page): { measuredWidth: number; measuredHeight: number } { public measurePage(page: Page): { measuredWidth: number; measuredHeight: number } {
// If background does not span under statusbar - reduce available height. // If background does not span under statusbar - reduce available height.
let heightSpec: number = this._heightMeasureSpec; let heightSpec: number = this._heightMeasureSpec;
if (page && !page.backgroundSpanUnderStatusBar && !this.parent) { if (page && !page.backgroundSpanUnderStatusBar && !this.parent) {
@ -246,7 +262,7 @@ export class Frame extends frameCommon.Frame {
heightSpec = utils.layout.makeMeasureSpec(height - statusBarHeight, heightMode); heightSpec = utils.layout.makeMeasureSpec(height - statusBarHeight, heightMode);
} }
return view.View.measureChild(this, page, this._widthMeasureSpec, heightSpec); return View.measureChild(this, page, this._widthMeasureSpec, heightSpec);
} }
public onLayout(left: number, top: number, right: number, bottom: number): void { public onLayout(left: number, top: number, right: number, bottom: number): void {
@ -259,7 +275,7 @@ export class Frame extends frameCommon.Frame {
} }
} }
public layoutPage(page: pages.Page): void { public layoutPage(page: Page): void {
if (page && (<any>page)._viewWillDisappear) { if (page && (<any>page)._viewWillDisappear) {
//https://github.com/NativeScript/NativeScript/issues/1201 //https://github.com/NativeScript/NativeScript/issues/1201
return; return;
@ -268,7 +284,7 @@ export class Frame extends frameCommon.Frame {
// If background does not span under statusbar - reduce available height and adjust top offset. // If background does not span under statusbar - reduce available height and adjust top offset.
let statusBarHeight = (page && !page.backgroundSpanUnderStatusBar && !this.parent) ? uiUtils.ios.getStatusBarHeight() : 0; let statusBarHeight = (page && !page.backgroundSpanUnderStatusBar && !this.parent) ? uiUtils.ios.getStatusBarHeight() : 0;
view.View.layoutChild(this, page, 0, statusBarHeight, this._right, this._bottom); View.layoutChild(this, page, 0, statusBarHeight, this._right, this._bottom);
} }
public get navigationBarHeight(): number { public get navigationBarHeight(): number {
@ -320,19 +336,17 @@ export class Frame extends frameCommon.Frame {
} }
} }
class TransitionDelegate extends NSObject { let transitionDelegates = new Array<TransitionDelegate>();
static new(): TransitionDelegate {
return <TransitionDelegate>super.new();
}
private _owner: UINavigationControllerImpl; class TransitionDelegate extends NSObject {
private _id: string; private _id: string;
public initWithOwnerId(owner: UINavigationControllerImpl, id: string): TransitionDelegate { public static initWithOwnerId(id: string): TransitionDelegate {
this._owner = owner; let delegate = <TransitionDelegate>TransitionDelegate.new();
this._owner.transitionDelegates.push(this); delegate._id = id;
this._id = id; transitionDelegates.push(delegate);
return this;
return delegate;
} }
public animationWillStart(animationID: string, context: any): void { public animationWillStart(animationID: string, context: any): void {
@ -347,11 +361,9 @@ class TransitionDelegate extends NSObject {
trace.write(`CANCEL ${this._id}`, trace.categories.Transition); trace.write(`CANCEL ${this._id}`, trace.categories.Transition);
} }
if (this._owner) { var index = transitionDelegates.indexOf(this);
var index = this._owner.transitionDelegates.indexOf(this);
if (index > -1) { if (index > -1) {
this._owner.transitionDelegates.splice(index, 1); transitionDelegates.splice(index, 1);
}
} }
} }
@ -362,16 +374,52 @@ class TransitionDelegate extends NSObject {
} }
var _defaultTransitionDuration = 0.35; var _defaultTransitionDuration = 0.35;
class UINavigationControllerImpl extends UINavigationController implements UINavigationControllerDelegate {
class UINavigationControllerAnimatedDelegate extends NSObject implements UINavigationControllerDelegate {
public static ObjCProtocols = [UINavigationControllerDelegate]; public static ObjCProtocols = [UINavigationControllerDelegate];
navigationControllerAnimationControllerForOperationFromViewControllerToViewController(
navigationController: UINavigationController,
operation: number,
fromVC: UIViewController,
toVC: UIViewController): UIViewControllerAnimatedTransitioning {
let viewController: UIViewController;
switch (operation) {
case UINavigationControllerOperation.UINavigationControllerOperationPush:
viewController = toVC;
break;
case UINavigationControllerOperation.UINavigationControllerOperationPop:
viewController = fromVC;
break;
}
if (!viewController) {
return null;
}
let navigationTransition = <definition.NavigationTransition>viewController[TRANSITION];
if (!navigationTransition) {
return null;
}
trace.write(`UINavigationControllerImpl.navigationControllerAnimationControllerForOperationFromViewControllerToViewController(${operation}, ${fromVC}, ${toVC}), transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle);
if (!transitionModule) {
transitionModule = require("ui/transition");
}
let curve = _getNativeCurve(navigationTransition);
let animationController = transitionModule._createIOSAnimatedTransitioning(navigationTransition, curve, operation, fromVC, toVC);
return animationController;
}
}
class UINavigationControllerImpl extends UINavigationController {
private _owner: WeakRef<Frame>; private _owner: WeakRef<Frame>;
private _transitionDelegates: Array<TransitionDelegate>;
public static initWithOwner(owner: WeakRef<Frame>): UINavigationControllerImpl { public static initWithOwner(owner: WeakRef<Frame>): UINavigationControllerImpl {
var controller = <UINavigationControllerImpl>UINavigationControllerImpl.new(); var controller = <UINavigationControllerImpl>UINavigationControllerImpl.new();
controller._owner = owner; controller._owner = owner;
controller._transitionDelegates = new Array<TransitionDelegate>();
return controller; return controller;
} }
@ -379,10 +427,6 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
return this._owner.get(); return this._owner.get();
} }
get transitionDelegates(): Array<TransitionDelegate> {
return this._transitionDelegates;
}
public viewDidLoad(): void { public viewDidLoad(): void {
let owner = this._owner.get(); let owner = this._owner.get();
if (owner) { if (owner) {
@ -398,66 +442,62 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
} }
} }
public supportedInterfaceOrientation(): number { private animateWithDuration(navigationTransition: definition.NavigationTransition,
return UIInterfaceOrientationMask.UIInterfaceOrientationMaskAll; nativeTransition: UIViewAnimationTransition,
transitionType: string,
baseCallback: Function): void {
let duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration;
let curve = _getNativeCurve(navigationTransition);
let transitionTraced = trace.isCategorySet(trace.categories.Transition);
let transitionDelegate: TransitionDelegate;
if (transitionTraced) {
let id = _getTransitionId(nativeTransition, transitionType);
transitionDelegate = TransitionDelegate.initWithOwnerId(id);
} }
public pushViewControllerAnimated(viewController: UIViewController, animated: boolean): void {
var navigationTransition = <definition.NavigationTransition>viewController[TRANSITION];
trace.write(`UINavigationControllerImpl.pushViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle);
if (!animated || !navigationTransition) {
super.pushViewControllerAnimated(viewController, animated);
return;
}
var nativeTransition = _getNativeTransition(navigationTransition, true);
if (!nativeTransition) {
super.pushViewControllerAnimated(viewController, animated);
return;
}
var duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration;
var curve = _getNativeCurve(navigationTransition);
var id = _getTransitionId(nativeTransition, "push");
var transitionDelegate = TransitionDelegate.new().initWithOwnerId(this, id);
UIView.animateWithDurationAnimations(duration, () => { UIView.animateWithDurationAnimations(duration, () => {
if (transitionTraced) {
UIView.setAnimationDelegate(transitionDelegate); UIView.setAnimationDelegate(transitionDelegate);
}
UIView.setAnimationWillStartSelector("animationWillStart"); UIView.setAnimationWillStartSelector("animationWillStart");
UIView.setAnimationDidStopSelector("animationDidStop"); UIView.setAnimationDidStopSelector("animationDidStop");
UIView.setAnimationCurve(curve); UIView.setAnimationCurve(curve);
super.pushViewControllerAnimated(viewController, false); baseCallback();
UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true); UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true);
}); });
} }
public pushViewControllerAnimated(viewController: UIViewController, animated: boolean): void {
let navigationTransition = <definition.NavigationTransition>viewController[TRANSITION];
trace.write(`UINavigationControllerImpl.pushViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle);
let nativeTransition = _getNativeTransition(navigationTransition, true);
if (!animated || !navigationTransition || !nativeTransition) {
super.pushViewControllerAnimated(viewController, animated);
return;
}
this.animateWithDuration(navigationTransition, nativeTransition, "push", () => {
super.pushViewControllerAnimated(viewController, false);
});
}
public setViewControllersAnimated(viewControllers: NSArray, animated: boolean): void { public setViewControllersAnimated(viewControllers: NSArray, animated: boolean): void {
var viewController = viewControllers.lastObject; var viewController = viewControllers.lastObject;
var navigationTransition = <definition.NavigationTransition>viewController[TRANSITION]; var navigationTransition = <definition.NavigationTransition>viewController[TRANSITION];
trace.write(`UINavigationControllerImpl.setViewControllersAnimated(${viewControllers}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle); trace.write(`UINavigationControllerImpl.setViewControllersAnimated(${viewControllers}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle);
if (!animated || !navigationTransition) { let nativeTransition = _getNativeTransition(navigationTransition, true);
if (!animated || !navigationTransition || !nativeTransition) {
super.setViewControllersAnimated(viewControllers, animated); super.setViewControllersAnimated(viewControllers, animated);
return; return;
} }
var nativeTransition = _getNativeTransition(navigationTransition, true); this.animateWithDuration(navigationTransition, nativeTransition, "set", () => {
if (!nativeTransition) {
super.setViewControllersAnimated(viewControllers, animated);
return;
}
var duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration;
var curve = _getNativeCurve(navigationTransition);
var id = _getTransitionId(nativeTransition, "set");
var transitionDelegate = TransitionDelegate.new().initWithOwnerId(this, id);
UIView.animateWithDurationAnimations(duration, () => {
UIView.setAnimationDelegate(transitionDelegate);
UIView.setAnimationWillStartSelector("animationWillStart");
UIView.setAnimationDidStopSelector("animationDidStop");
UIView.setAnimationCurve(curve);
super.setViewControllersAnimated(viewControllers, false); super.setViewControllersAnimated(viewControllers, false);
UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true);
}); });
} }
@ -466,92 +506,44 @@ class UINavigationControllerImpl extends UINavigationController implements UINav
var navigationTransition = <definition.NavigationTransition>lastViewController[TRANSITION]; var navigationTransition = <definition.NavigationTransition>lastViewController[TRANSITION];
trace.write(`UINavigationControllerImpl.popViewControllerAnimated(${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle); trace.write(`UINavigationControllerImpl.popViewControllerAnimated(${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle);
if (!animated || !navigationTransition) { if (navigationTransition && navigationTransition.name === "non-animated") {
return super.popViewControllerAnimated(animated);
}
if (navigationTransition.name === "non-animated") {
//https://github.com/NativeScript/NativeScript/issues/1787 //https://github.com/NativeScript/NativeScript/issues/1787
return super.popViewControllerAnimated(false); return super.popViewControllerAnimated(false);
} }
var nativeTransition = _getNativeTransition(navigationTransition, false); var nativeTransition = _getNativeTransition(navigationTransition, false);
if (!nativeTransition) { if (!animated || !navigationTransition || !nativeTransition) {
return super.popViewControllerAnimated(animated); return super.popViewControllerAnimated(animated);
} }
var duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration; this.animateWithDuration(navigationTransition, nativeTransition, "pop", () => {
var curve = _getNativeCurve(navigationTransition);
var id = _getTransitionId(nativeTransition, "pop");
var transitionDelegate = TransitionDelegate.new().initWithOwnerId(this, id);
UIView.animateWithDurationAnimations(duration, () => {
UIView.setAnimationDelegate(transitionDelegate);
UIView.setAnimationWillStartSelector("animationWillStart");
UIView.setAnimationDidStopSelector("animationDidStop");
UIView.setAnimationCurve(curve);
super.popViewControllerAnimated(false); super.popViewControllerAnimated(false);
UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true);
}); });
return null; return null;
} }
public popToViewControllerAnimated(viewController: UIViewController, animated: boolean): NSArray { public popToViewControllerAnimated(viewController: UIViewController, animated: boolean): NSArray {
var lastViewController = this.viewControllers.lastObject; let lastViewController = this.viewControllers.lastObject;
var navigationTransition = <definition.NavigationTransition>lastViewController[TRANSITION]; let navigationTransition = <definition.NavigationTransition>lastViewController[TRANSITION];
trace.write(`UINavigationControllerImpl.popToViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle); trace.write(`UINavigationControllerImpl.popToViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle);
if (!animated || !navigationTransition) {
return super.popToViewControllerAnimated(viewController, animated);
}
if (navigationTransition.name === "non-animated") { if (navigationTransition && navigationTransition.name === "non-animated") {
//https://github.com/NativeScript/NativeScript/issues/1787 //https://github.com/NativeScript/NativeScript/issues/1787
return super.popToViewControllerAnimated(viewController, false); return super.popToViewControllerAnimated(viewController, false);
} }
var nativeTransition = _getNativeTransition(navigationTransition, false); let nativeTransition = _getNativeTransition(navigationTransition, false);
if (!nativeTransition) { if (!animated || !navigationTransition || !nativeTransition) {
return super.popToViewControllerAnimated(viewController, animated); return super.popToViewControllerAnimated(viewController, animated);
} }
var duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration; this.animateWithDuration(navigationTransition, nativeTransition, "popTo", () => {
var curve = _getNativeCurve(navigationTransition);
var id = _getTransitionId(nativeTransition, "popTo");
var transitionDelegate = TransitionDelegate.new().initWithOwnerId(this, id);
UIView.animateWithDurationAnimations(duration, () => {
UIView.setAnimationDelegate(transitionDelegate);
UIView.setAnimationWillStartSelector("animationWillStart");
UIView.setAnimationDidStopSelector("animationDidStop");
UIView.setAnimationCurve(curve);
super.popToViewControllerAnimated(viewController, false); super.popToViewControllerAnimated(viewController, false);
UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true);
}); });
return null; return null;
} }
public navigationControllerAnimationControllerForOperationFromViewControllerToViewController(navigationController: UINavigationController, operation: number, fromVC: UIViewController, toVC: UIViewController): UIViewControllerAnimatedTransitioning {
var viewController: UIViewController;
switch (operation) {
case UINavigationControllerOperation.UINavigationControllerOperationPush:
viewController = toVC;
break;
case UINavigationControllerOperation.UINavigationControllerOperationPop:
viewController = fromVC;
break;
}
if (!viewController) {
return null;
}
var navigationTransition = <definition.NavigationTransition>viewController[TRANSITION];
if (!navigationTransition) {
return null;
}
trace.write(`UINavigationControllerImpl.navigationControllerAnimationControllerForOperationFromViewControllerToViewController(${operation}, ${fromVC}, ${toVC}), transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle);
var _transitionModule: typeof transitionModule = require("ui/transition");
return _transitionModule._createIOSAnimatedTransitioning(navigationTransition, operation, fromVC, toVC);
}
} }
function _getTransitionId(nativeTransition: UIViewAnimationTransition, transitionType: string): string { function _getTransitionId(nativeTransition: UIViewAnimationTransition, transitionType: string): string {
@ -568,7 +560,7 @@ function _getTransitionId(nativeTransition: UIViewAnimationTransition, transitio
} }
function _getNativeTransition(navigationTransition: definition.NavigationTransition, push: boolean): UIViewAnimationTransition { function _getNativeTransition(navigationTransition: definition.NavigationTransition, push: boolean): UIViewAnimationTransition {
if (navigationTransition.name) { if (navigationTransition && navigationTransition.name) {
switch (navigationTransition.name.toLowerCase()) { switch (navigationTransition.name.toLowerCase()) {
case "flip": case "flip":
case "flipright": case "flipright":
@ -582,22 +574,23 @@ function _getNativeTransition(navigationTransition: definition.NavigationTransit
return push ? UIViewAnimationTransition.UIViewAnimationTransitionCurlDown : UIViewAnimationTransition.UIViewAnimationTransitionCurlUp; return push ? UIViewAnimationTransition.UIViewAnimationTransitionCurlDown : UIViewAnimationTransition.UIViewAnimationTransitionCurlUp;
} }
} }
return null; return null;
} }
export function _getNativeCurve(transition: definition.NavigationTransition): UIViewAnimationCurve { export function _getNativeCurve(transition: definition.NavigationTransition): UIViewAnimationCurve {
if (transition.curve) { if (transition.curve) {
switch (transition.curve) { switch (transition.curve) {
case enums.AnimationCurve.easeIn: case AnimationCurve.easeIn:
trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseIn.", trace.categories.Transition); trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseIn.", trace.categories.Transition);
return UIViewAnimationCurve.UIViewAnimationCurveEaseIn; return UIViewAnimationCurve.UIViewAnimationCurveEaseIn;
case enums.AnimationCurve.easeOut: case AnimationCurve.easeOut:
trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseOut.", trace.categories.Transition); trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseOut.", trace.categories.Transition);
return UIViewAnimationCurve.UIViewAnimationCurveEaseOut; return UIViewAnimationCurve.UIViewAnimationCurveEaseOut;
case enums.AnimationCurve.easeInOut: case AnimationCurve.easeInOut:
trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseInOut.", trace.categories.Transition); trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseInOut.", trace.categories.Transition);
return UIViewAnimationCurve.UIViewAnimationCurveEaseInOut; return UIViewAnimationCurve.UIViewAnimationCurveEaseInOut;
case enums.AnimationCurve.linear: case AnimationCurve.linear:
trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveLinear.", trace.categories.Transition); trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveLinear.", trace.categories.Transition);
return UIViewAnimationCurve.UIViewAnimationCurveLinear; return UIViewAnimationCurve.UIViewAnimationCurveLinear;
default: default:
@ -618,10 +611,9 @@ class iOSFrame implements definition.iOSFrame {
constructor(owner: Frame) { constructor(owner: Frame) {
this._controller = UINavigationControllerImpl.initWithOwner(new WeakRef(owner)); this._controller = UINavigationControllerImpl.initWithOwner(new WeakRef(owner));
this._controller.delegate = this._controller;
this._controller.automaticallyAdjustsScrollViewInsets = false; this._controller.automaticallyAdjustsScrollViewInsets = false;
//this.showNavigationBar = false; //this.showNavigationBar = false;
this._navBarVisibility = enums.NavigationBarVisibility.auto; this._navBarVisibility = NavigationBarVisibility.auto;
} }
public get controller() { public get controller() {

View File

@ -9,6 +9,7 @@ import {DeviceType} from "ui/enums";
global.moduleMerge(pageCommon, exports); global.moduleMerge(pageCommon, exports);
var ENTRY = "_entry"; var ENTRY = "_entry";
var DELEGATE = "_delegate";
function isBackNavigation(frame: any, entry): boolean { function isBackNavigation(frame: any, entry): boolean {
if (!frame) { if (!frame) {
@ -177,6 +178,13 @@ class UIViewControllerImpl extends UIViewController {
frame._updateActionBar(page); frame._updateActionBar(page);
page.onNavigatedTo(isBack); page.onNavigatedTo(isBack);
// If page was shown with custom animation - we need to set the navigationController.delegate to the animatedDelegate.
frame.ios.controller.delegate = this[DELEGATE];
// Workaround for disabled backswipe on second custom native transition
this.navigationController.interactivePopGestureRecognizer.delegate = this.navigationController;
frame._processNavigationQueue(page); frame._processNavigationQueue(page);
} }
}; };

5
ui/transition/fade-transition.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import {Transition} from "ui/transition";
export class FadeTransition extends Transition {
constructor(duration: number, nativeCurve: any);
}

5
ui/transition/slide-transition.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import {Transition} from "ui/transition";
export class SlideTransition extends Transition {
constructor(direction: string, duration: number, nativeCurve: any);
}

View File

@ -9,7 +9,7 @@
} }
export class Transition { export class Transition {
constructor(duration: number, curve: any); constructor(duration: number, nativeCurve: any);
public getDuration(): number; public getDuration(): number;
public getCurve(): any; public getCurve(): any;
public animateIOSTransition(containerView: any, fromView: any, toView: any, operation: any, completion: (finished: boolean) => void): void; public animateIOSTransition(containerView: any, fromView: any, toView: any, operation: any, completion: (finished: boolean) => void): void;
@ -24,6 +24,6 @@
export function _onFragmentShown(fragment: any, isBack: boolean): void; export function _onFragmentShown(fragment: any, isBack: boolean): void;
export function _onFragmentHidden(fragment: any, isBack: boolean): void; export function _onFragmentHidden(fragment: any, isBack: boolean): void;
export function _createIOSAnimatedTransitioning(navigationTransition: frame.NavigationTransition, operation: number, fromVC: any, toVC: any): any; export function _createIOSAnimatedTransitioning(navigationTransition: frame.NavigationTransition, nativeCurve: any, operation: number, fromVC: any, toVC: any): any;
//@endprivate //@endprivate
} }

View File

@ -2,6 +2,11 @@
import frame = require("ui/frame"); import frame = require("ui/frame");
import types = require("utils/types"); import types = require("utils/types");
import trace = require("trace"); import trace = require("trace");
import * as _slideTransitionModule from "./slide-transition";
import * as _fadeTransitionModule from "./fade-transition";
var slideTransitionModule: typeof _slideTransitionModule;
var fadeTransitionModule: typeof _fadeTransitionModule;
module UIViewControllerAnimatedTransitioningMethods { module UIViewControllerAnimatedTransitioningMethods {
let methodSignature = NSMethodSignature.signatureWithObjCTypes("v@:c"); let methodSignature = NSMethodSignature.signatureWithObjCTypes("v@:c");
@ -31,7 +36,7 @@ class AnimatedTransitioning extends NSObject implements UIViewControllerAnimated
impl._fromVC = fromVC; impl._fromVC = fromVC;
impl._toVC = toVC; impl._toVC = toVC;
return impl; return impl;
} }
public animateTransition(transitionContext: any): void { public animateTransition(transitionContext: any): void {
let containerView = transitionContext.valueForKey("containerView"); let containerView = transitionContext.valueForKey("containerView");
@ -60,19 +65,16 @@ class AnimatedTransitioning extends NSObject implements UIViewControllerAnimated
} }
} }
var transitionId = 0;
export class Transition implements definition.Transition { export class Transition implements definition.Transition {
private _duration: number; private _duration: number;
private _curve: UIViewAnimationCurve; private _curve: UIViewAnimationCurve;
private _id: number; private _id: number;
constructor(duration: number, curve: any) { constructor(duration: number, curve: UIViewAnimationCurve = UIViewAnimationCurve.UIViewAnimationCurveEaseInOut) {
this._duration = duration ? (duration / 1000) : 0.35; this._duration = duration ? (duration / 1000) : 0.35;
if (curve) { this._curve = curve;
this._curve = (<any>frame)._getNativeCurve(curve); this._id = transitionId++;
}
else {
this._curve = UIViewAnimationCurve.UIViewAnimationCurveEaseInOut;
}
} }
public getDuration(): number { public getDuration(): number {
@ -96,19 +98,25 @@ export class Transition implements definition.Transition {
} }
} }
export function _createIOSAnimatedTransitioning(navigationTransition: frame.NavigationTransition, operation: UINavigationControllerOperation, fromVC: UIViewController, toVC: UIViewController): UIViewControllerAnimatedTransitioning { export function _createIOSAnimatedTransitioning(navigationTransition: frame.NavigationTransition, nativeCurve: UIViewAnimationCurve, operation: UINavigationControllerOperation, fromVC: UIViewController, toVC: UIViewController): UIViewControllerAnimatedTransitioning {
var transition: definition.Transition; let transition: definition.Transition;
if (navigationTransition.name) { if (navigationTransition.name) {
var name = navigationTransition.name.toLowerCase(); let name = navigationTransition.name.toLowerCase();
if (name.indexOf("slide") === 0) { if (name.indexOf("slide") === 0) {
var slideTransitionModule = require("./slide-transition"); let direction = name.substr("slide".length) || "left"; //Extract the direction from the string
var direction = name.substr("slide".length) || "left"; //Extract the direction from the string if (!slideTransitionModule) {
transition = new slideTransitionModule.SlideTransition(direction, navigationTransition.duration, navigationTransition.curve); slideTransitionModule = require("./slide-transition");
}
transition = new slideTransitionModule.SlideTransition(direction, navigationTransition.duration, nativeCurve);
} }
else if (name === "fade") { else if (name === "fade") {
var fadeTransitionModule = require("./fade-transition"); if (!fadeTransitionModule) {
transition = new fadeTransitionModule.FadeTransition(navigationTransition.duration, navigationTransition.curve); fadeTransitionModule = require("./fade-transition");
}
transition = new fadeTransitionModule.FadeTransition(navigationTransition.duration, nativeCurve);
} }
} }
else { else {