From 429646f39272eefec06f3db944c54c7a4be7cc44 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Fri, 25 Mar 2016 12:01:02 +0200 Subject: [PATCH] Fix swipe-back in iOS --- CrossPlatformModules.csproj | 4 +- ios.d.ts | 4 +- trace/trace.d.ts | 6 + trace/trace.ts | 4 + tsconfig.json | 2 + ui/frame/frame-common.ts | 2 +- ui/frame/frame.ios.ts | 282 ++++++++++++++-------------- ui/page/page.ios.ts | 8 + ui/transition/fade-transition.d.ts | 5 + ui/transition/slide-transition.d.ts | 5 + ui/transition/transition.d.ts | 4 +- ui/transition/transition.ios.ts | 44 +++-- 12 files changed, 201 insertions(+), 169 deletions(-) create mode 100644 ui/transition/fade-transition.d.ts create mode 100644 ui/transition/slide-transition.d.ts diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj index 45e475464..88f3c1311 100644 --- a/CrossPlatformModules.csproj +++ b/CrossPlatformModules.csproj @@ -768,6 +768,8 @@ + + @@ -2201,7 +2203,7 @@ False - + \ No newline at end of file diff --git a/ios.d.ts b/ios.d.ts index d1d6c9ff1..3c7089f86 100644 --- a/ios.d.ts +++ b/ios.d.ts @@ -20624,8 +20624,8 @@ interface UIViewControllerContextTransitioning { finalFrameForViewController(vc: UIViewController): CGRect; } interface UIViewControllerAnimatedTransitioning { - transitionDuration(transitionContext: any): number; - animateTransition(transitionContext: any): void; + transitionDuration(transitionContext: UIViewControllerContextTransitioning): number; + animateTransition(transitionContext: UIViewControllerContextTransitioning): void; animationEnded?(transitionCompleted: boolean): void; } interface UIViewControllerInteractiveTransitioning { diff --git a/trace/trace.d.ts b/trace/trace.d.ts index dcc83817a..bf3242ec9 100644 --- a/trace/trace.d.ts +++ b/trace/trace.d.ts @@ -41,6 +41,12 @@ declare module "trace" { */ 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. * @param message The message to be written. diff --git a/trace/trace.ts b/trace/trace.ts index 98390ad7b..9b6b4e3ab 100644 --- a/trace/trace.ts +++ b/trace/trace.ts @@ -14,6 +14,10 @@ export function disable() { _enabled = false; } +export function isCategorySet(category: string): boolean { + return category in _categories; +} + export function addWriter(writer: definition.TraceWriter) { _writers.push(writer); } diff --git a/tsconfig.json b/tsconfig.json index facfb3021..fa4b55a8b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -688,6 +688,8 @@ "ui/transition/transition.android.ts", "ui/transition/transition.d.ts", "ui/transition/transition.ios.ts", + "ui/transition/fade-transition.d.ts", + "ui/transition/slide-transition.d.ts", "ui/utils.d.ts", "ui/utils.ios.ts", "ui/web-view/web-view-common.ts", diff --git a/ui/frame/frame-common.ts b/ui/frame/frame-common.ts index fcf0adeb0..0354cab0d 100644 --- a/ui/frame/frame-common.ts +++ b/ui/frame/frame-common.ts @@ -402,7 +402,7 @@ export class Frame extends CustomLayoutView implements definition.Frame { return entry.transitionAndroid; } - if (entry && isDefined(entry.transition)) { + if (isDefined(entry.transition)) { return entry.transition; } } diff --git a/ui/frame/frame.ios.ts b/ui/frame/frame.ios.ts index 70629796d..166f5126c 100644 --- a/ui/frame/frame.ios.ts +++ b/ui/frame/frame.ios.ts @@ -1,25 +1,29 @@ import frameCommon = require("./frame-common"); import definition = require("ui/frame"); import trace = require("trace"); -import pages = require("ui/page"); -import enums = require("ui/enums"); +import {Page} from "ui/page"; +import {NavigationBarVisibility, AnimationCurve} from "ui/enums"; import utils = require("utils/utils"); -import view = require("ui/core/view"); +import {View} from "ui/core/view"; import uiUtils = require("ui/utils"); import * as types from "utils/types"; -import * as transitionModule from "ui/transition"; import application = require("application"); +import * as _transitionModule from "ui/transition"; + +var transitionModule: typeof _transitionModule; global.moduleMerge(frameCommon, exports); var ENTRY = "_entry"; var NAV_DEPTH = "_navDepth"; var TRANSITION = "_transition"; +var DELEGATE = "_delegate"; var navDepth = -1; export class Frame extends frameCommon.Frame { private _ios: iOSFrame; private _paramToNavigate: any; + public _animatedDelegate = UINavigationControllerAnimatedDelegate.new(); public _shouldSkipNativePop: boolean = false; public _navigateToEntry: definition.BackstackEntry; @@ -65,16 +69,17 @@ export class Frame extends frameCommon.Frame { 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); - var viewController: UIViewController = backstackEntry.resolvedPage.ios; + let viewController: UIViewController = backstackEntry.resolvedPage.ios; if (!viewController) { throw new Error("Required page does not have a viewController created."); } 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) { - var navigationTransition = this._getNavigationTransition(backstackEntry.entry); + navigationTransition = this._getNavigationTransition(backstackEntry.entry); if (navigationTransition) { viewController[TRANSITION] = navigationTransition; } @@ -84,6 +89,16 @@ export class Frame extends frameCommon.Frame { 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; 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); 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) { - case enums.NavigationBarVisibility.always: + case NavigationBarVisibility.always: return true; - case enums.NavigationBarVisibility.never: + case NavigationBarVisibility.never: return false; - case enums.NavigationBarVisibility.auto: + case NavigationBarVisibility.auto: let newValue: boolean; 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.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); } - 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. let heightSpec: number = this._heightMeasureSpec; if (page && !page.backgroundSpanUnderStatusBar && !this.parent) { @@ -246,7 +262,7 @@ export class Frame extends frameCommon.Frame { 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 { @@ -259,7 +275,7 @@ export class Frame extends frameCommon.Frame { } } - public layoutPage(page: pages.Page): void { + public layoutPage(page: Page): void { if (page && (page)._viewWillDisappear) { //https://github.com/NativeScript/NativeScript/issues/1201 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. 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 { @@ -320,19 +336,17 @@ export class Frame extends frameCommon.Frame { } } -class TransitionDelegate extends NSObject { - static new(): TransitionDelegate { - return super.new(); - } +let transitionDelegates = new Array(); - private _owner: UINavigationControllerImpl; +class TransitionDelegate extends NSObject { private _id: string; - public initWithOwnerId(owner: UINavigationControllerImpl, id: string): TransitionDelegate { - this._owner = owner; - this._owner.transitionDelegates.push(this); - this._id = id; - return this; + public static initWithOwnerId(id: string): TransitionDelegate { + let delegate = TransitionDelegate.new(); + delegate._id = id; + transitionDelegates.push(delegate); + + return delegate; } public animationWillStart(animationID: string, context: any): void { @@ -347,11 +361,9 @@ class TransitionDelegate extends NSObject { trace.write(`CANCEL ${this._id}`, trace.categories.Transition); } - if (this._owner) { - var index = this._owner.transitionDelegates.indexOf(this); - if (index > -1) { - this._owner.transitionDelegates.splice(index, 1); - } + var index = transitionDelegates.indexOf(this); + if (index > -1) { + transitionDelegates.splice(index, 1); } } @@ -362,16 +374,52 @@ class TransitionDelegate extends NSObject { } var _defaultTransitionDuration = 0.35; -class UINavigationControllerImpl extends UINavigationController implements UINavigationControllerDelegate { + +class UINavigationControllerAnimatedDelegate extends NSObject implements 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 = 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; - private _transitionDelegates: Array; public static initWithOwner(owner: WeakRef): UINavigationControllerImpl { var controller = UINavigationControllerImpl.new(); controller._owner = owner; - controller._transitionDelegates = new Array(); return controller; } @@ -379,10 +427,6 @@ class UINavigationControllerImpl extends UINavigationController implements UINav return this._owner.get(); } - get transitionDelegates(): Array { - return this._transitionDelegates; - } - public viewDidLoad(): void { let owner = this._owner.get(); if (owner) { @@ -398,66 +442,62 @@ class UINavigationControllerImpl extends UINavigationController implements UINav } } - public supportedInterfaceOrientation(): number { - return UIInterfaceOrientationMask.UIInterfaceOrientationMaskAll; - } + private animateWithDuration(navigationTransition: definition.NavigationTransition, + nativeTransition: UIViewAnimationTransition, + transitionType: string, + baseCallback: Function): void { - public pushViewControllerAnimated(viewController: UIViewController, animated: boolean): void { - var navigationTransition = viewController[TRANSITION]; - trace.write(`UINavigationControllerImpl.pushViewControllerAnimated(${viewController}, ${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle); + let duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration; + let curve = _getNativeCurve(navigationTransition); - if (!animated || !navigationTransition) { - super.pushViewControllerAnimated(viewController, animated); - return; + let transitionTraced = trace.isCategorySet(trace.categories.Transition); + let transitionDelegate: TransitionDelegate; + if (transitionTraced) { + let id = _getTransitionId(nativeTransition, transitionType); + transitionDelegate = TransitionDelegate.initWithOwnerId(id); } - 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.setAnimationDelegate(transitionDelegate); + if (transitionTraced) { + UIView.setAnimationDelegate(transitionDelegate); + } + UIView.setAnimationWillStartSelector("animationWillStart"); UIView.setAnimationDidStopSelector("animationDidStop"); UIView.setAnimationCurve(curve); - super.pushViewControllerAnimated(viewController, false); + baseCallback(); UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true); }); } + public pushViewControllerAnimated(viewController: UIViewController, animated: boolean): void { + let 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 { var viewController = viewControllers.lastObject; var navigationTransition = viewController[TRANSITION]; 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); return; } - var nativeTransition = _getNativeTransition(navigationTransition, true); - 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); + this.animateWithDuration(navigationTransition, nativeTransition, "set", () => { super.setViewControllersAnimated(viewControllers, false); - UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true); }); } @@ -466,92 +506,44 @@ class UINavigationControllerImpl extends UINavigationController implements UINav var navigationTransition = lastViewController[TRANSITION]; trace.write(`UINavigationControllerImpl.popViewControllerAnimated(${animated}); transition: ${JSON.stringify(navigationTransition)}`, trace.categories.NativeLifecycle); - if (!animated || !navigationTransition) { - return super.popViewControllerAnimated(animated); - } - - if (navigationTransition.name === "non-animated") { + if (navigationTransition && navigationTransition.name === "non-animated") { //https://github.com/NativeScript/NativeScript/issues/1787 return super.popViewControllerAnimated(false); } var nativeTransition = _getNativeTransition(navigationTransition, false); - if (!nativeTransition) { + if (!animated || !navigationTransition || !nativeTransition) { return super.popViewControllerAnimated(animated); } - var duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration; - 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); + this.animateWithDuration(navigationTransition, nativeTransition, "pop", () => { super.popViewControllerAnimated(false); - UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true); }); + return null; } public popToViewControllerAnimated(viewController: UIViewController, animated: boolean): NSArray { - var lastViewController = this.viewControllers.lastObject; - var navigationTransition = lastViewController[TRANSITION]; + let lastViewController = this.viewControllers.lastObject; + let navigationTransition = lastViewController[TRANSITION]; 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 return super.popToViewControllerAnimated(viewController, false); } - var nativeTransition = _getNativeTransition(navigationTransition, false); - if (!nativeTransition) { + let nativeTransition = _getNativeTransition(navigationTransition, false); + if (!animated || !navigationTransition || !nativeTransition) { return super.popToViewControllerAnimated(viewController, animated); } - var duration = navigationTransition.duration ? navigationTransition.duration / 1000 : _defaultTransitionDuration; - 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); + this.animateWithDuration(navigationTransition, nativeTransition, "popTo", () => { super.popToViewControllerAnimated(viewController, false); - UIView.setAnimationTransitionForViewCache(nativeTransition, this.view, true); }); + 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 = 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 { @@ -568,7 +560,7 @@ function _getTransitionId(nativeTransition: UIViewAnimationTransition, transitio } function _getNativeTransition(navigationTransition: definition.NavigationTransition, push: boolean): UIViewAnimationTransition { - if (navigationTransition.name) { + if (navigationTransition && navigationTransition.name) { switch (navigationTransition.name.toLowerCase()) { case "flip": case "flipright": @@ -582,22 +574,23 @@ function _getNativeTransition(navigationTransition: definition.NavigationTransit return push ? UIViewAnimationTransition.UIViewAnimationTransitionCurlDown : UIViewAnimationTransition.UIViewAnimationTransitionCurlUp; } } + return null; } export function _getNativeCurve(transition: definition.NavigationTransition): UIViewAnimationCurve { if (transition.curve) { switch (transition.curve) { - case enums.AnimationCurve.easeIn: + case AnimationCurve.easeIn: trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseIn.", trace.categories.Transition); return UIViewAnimationCurve.UIViewAnimationCurveEaseIn; - case enums.AnimationCurve.easeOut: + case AnimationCurve.easeOut: trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseOut.", trace.categories.Transition); return UIViewAnimationCurve.UIViewAnimationCurveEaseOut; - case enums.AnimationCurve.easeInOut: + case AnimationCurve.easeInOut: trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveEaseInOut.", trace.categories.Transition); return UIViewAnimationCurve.UIViewAnimationCurveEaseInOut; - case enums.AnimationCurve.linear: + case AnimationCurve.linear: trace.write("Transition curve resolved to UIViewAnimationCurve.UIViewAnimationCurveLinear.", trace.categories.Transition); return UIViewAnimationCurve.UIViewAnimationCurveLinear; default: @@ -618,10 +611,9 @@ class iOSFrame implements definition.iOSFrame { constructor(owner: Frame) { this._controller = UINavigationControllerImpl.initWithOwner(new WeakRef(owner)); - this._controller.delegate = this._controller; this._controller.automaticallyAdjustsScrollViewInsets = false; //this.showNavigationBar = false; - this._navBarVisibility = enums.NavigationBarVisibility.auto; + this._navBarVisibility = NavigationBarVisibility.auto; } public get controller() { @@ -648,4 +640,4 @@ class iOSFrame implements definition.iOSFrame { public set navBarVisibility(value: string) { this._navBarVisibility = value; } -} +} \ No newline at end of file diff --git a/ui/page/page.ios.ts b/ui/page/page.ios.ts index ec5c151a2..aa200716d 100644 --- a/ui/page/page.ios.ts +++ b/ui/page/page.ios.ts @@ -9,6 +9,7 @@ import {DeviceType} from "ui/enums"; global.moduleMerge(pageCommon, exports); var ENTRY = "_entry"; +var DELEGATE = "_delegate"; function isBackNavigation(frame: any, entry): boolean { if (!frame) { @@ -177,6 +178,13 @@ class UIViewControllerImpl extends UIViewController { frame._updateActionBar(page); 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); } }; diff --git a/ui/transition/fade-transition.d.ts b/ui/transition/fade-transition.d.ts new file mode 100644 index 000000000..184615c41 --- /dev/null +++ b/ui/transition/fade-transition.d.ts @@ -0,0 +1,5 @@ +import {Transition} from "ui/transition"; + +export class FadeTransition extends Transition { + constructor(duration: number, nativeCurve: any); +} \ No newline at end of file diff --git a/ui/transition/slide-transition.d.ts b/ui/transition/slide-transition.d.ts new file mode 100644 index 000000000..a5b1343f2 --- /dev/null +++ b/ui/transition/slide-transition.d.ts @@ -0,0 +1,5 @@ +import {Transition} from "ui/transition"; + +export class SlideTransition extends Transition { + constructor(direction: string, duration: number, nativeCurve: any); +} \ No newline at end of file diff --git a/ui/transition/transition.d.ts b/ui/transition/transition.d.ts index 639e97068..aba7adb17 100644 --- a/ui/transition/transition.d.ts +++ b/ui/transition/transition.d.ts @@ -9,7 +9,7 @@ } export class Transition { - constructor(duration: number, curve: any); + constructor(duration: number, nativeCurve: any); public getDuration(): number; public getCurve(): any; 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 _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 } \ No newline at end of file diff --git a/ui/transition/transition.ios.ts b/ui/transition/transition.ios.ts index 903981194..e9242d908 100644 --- a/ui/transition/transition.ios.ts +++ b/ui/transition/transition.ios.ts @@ -2,12 +2,17 @@ import frame = require("ui/frame"); import types = require("utils/types"); 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 { let methodSignature = NSMethodSignature.signatureWithObjCTypes("v@:c"); let invocation = NSInvocation.invocationWithMethodSignature(methodSignature); invocation.selector = "completeTransition:"; - + export function completeTransition(didComplete: boolean) { let didCompleteReference = new interop.Reference(interop.types.bool, didComplete); invocation.setArgumentAtIndex(didCompleteReference, 2); @@ -31,7 +36,7 @@ class AnimatedTransitioning extends NSObject implements UIViewControllerAnimated impl._fromVC = fromVC; impl._toVC = toVC; return impl; -} + } public animateTransition(transitionContext: any): void { let containerView = transitionContext.valueForKey("containerView"); @@ -60,19 +65,16 @@ class AnimatedTransitioning extends NSObject implements UIViewControllerAnimated } } +var transitionId = 0; export class Transition implements definition.Transition { private _duration: number; private _curve: UIViewAnimationCurve; private _id: number; - constructor(duration: number, curve: any) { + constructor(duration: number, curve: UIViewAnimationCurve = UIViewAnimationCurve.UIViewAnimationCurveEaseInOut) { this._duration = duration ? (duration / 1000) : 0.35; - if (curve) { - this._curve = (frame)._getNativeCurve(curve); - } - else { - this._curve = UIViewAnimationCurve.UIViewAnimationCurveEaseInOut; - } + this._curve = curve; + this._id = transitionId++; } 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 { - var transition: definition.Transition; +export function _createIOSAnimatedTransitioning(navigationTransition: frame.NavigationTransition, nativeCurve: UIViewAnimationCurve, operation: UINavigationControllerOperation, fromVC: UIViewController, toVC: UIViewController): UIViewControllerAnimatedTransitioning { + let transition: definition.Transition; if (navigationTransition.name) { - var name = navigationTransition.name.toLowerCase(); + let name = navigationTransition.name.toLowerCase(); if (name.indexOf("slide") === 0) { - var slideTransitionModule = require("./slide-transition"); - var direction = name.substr("slide".length) || "left"; //Extract the direction from the string - transition = new slideTransitionModule.SlideTransition(direction, navigationTransition.duration, navigationTransition.curve); + let direction = name.substr("slide".length) || "left"; //Extract the direction from the string + if (!slideTransitionModule) { + slideTransitionModule = require("./slide-transition"); + } + + transition = new slideTransitionModule.SlideTransition(direction, navigationTransition.duration, nativeCurve); } else if (name === "fade") { - var fadeTransitionModule = require("./fade-transition"); - transition = new fadeTransitionModule.FadeTransition(navigationTransition.duration, navigationTransition.curve); + if (!fadeTransitionModule) { + fadeTransitionModule = require("./fade-transition"); + } + + transition = new fadeTransitionModule.FadeTransition(navigationTransition.duration, nativeCurve); } } else { @@ -120,4 +128,4 @@ export function _createIOSAnimatedTransitioning(navigationTransition: frame.Navi } return null; -} +} \ No newline at end of file