protected void StartInteractiveTransition(IUIViewControllerContextTransitioning transitionCtx)
        {
            SlidingViewController sliding       = this.SlidingViewController;
            UIViewController      topController = sliding.GetViewControllerForKey(ECSlidingViewController.ECTransitionContextTopViewControllerKey);

            // Disable user interaction of top controller's view
            topController.View.UserInteractionEnabled = false;
            if (_interactive)
            {
                UIViewController underController       = sliding.GetViewControllerForKey(ECSlidingViewController.ECTransitionContextUnderLeftControllerKey);
                RectangleF       underViewInitialFrame = sliding.GetInitialFrameForViewController(underController);
                RectangleF       underViewFinalFrame   = sliding.GetFinalFrameForViewController(underController);

                // Update frame of under controller view
                underController.View.Frame = underViewInitialFrame.IsEmpty ? underViewFinalFrame : underViewInitialFrame;
                // Insert under view below top view
                sliding.ContainerView.InsertSubviewBelow(underController.View, topController.View);

                // Do some calculation
                float finalLeftEdge   = sliding.GetFinalFrameForViewController(topController).GetMinX();
                float initialLeftEdge = sliding.GetInitialFrameForViewController(topController).GetMinX();

                _fullWidth           = Math.Abs(finalLeftEdge - initialLeftEdge);
                _positiveLeftToRight = initialLeftEdge < finalLeftEdge;
            }
            else
            {
                this.AnimationController.AnimateTransition(transitionCtx);
            }
            // Enable user interaction of top controller's view
            topController.View.UserInteractionEnabled = true;
        }
        internal void PanChanged(SlidingViewController slidingController, UIView topView, float translationX, float velocityX)
        {
            if (!_interactive)
            {
                return;
            }

            RectangleF initialFrame = _initialTopViewFrame;
            float      newLeftEdge  = initialFrame.X + translationX;

            // Calculate left edge
            if (newLeftEdge < 0)
            {
                newLeftEdge = 0;
            }
            else if (newLeftEdge > slidingController.AnchorRightRevealAmount)
            {
                newLeftEdge = slidingController.AnchorRightRevealAmount;
            }
            // Update top view frame
            initialFrame.X = newLeftEdge;
            topView.Frame  = initialFrame;
            // Update transition
            float percentComplete = ((!_positiveLeftToRight ? translationX * -1f : translationX) / _fullWidth);

            percentComplete = percentComplete < 0   ? 0   : percentComplete;
            percentComplete = percentComplete > 100 ? 100 : percentComplete;

            slidingController.UpdateInteractiveTransition(percentComplete);
        }
        internal void PanBegan(SlidingViewController slidingController, UIView topView, float translationX, float velocityX)
        {
            bool movingRight = velocityX > 0;

            _initialTopViewFrame = ((CALayer)topView.Layer.PresentationLayer).Frame;
            _interactive         = true;

            ECSlidingViewControllerTopViewPosition pos = slidingController.CurrentTopViewPosition;

            // Move sliding panel
            if (ECSlidingViewControllerTopViewPosition.Centered == pos && slidingController.UnderLeftViewController != null && movingRight)
            {
                slidingController.AnchorTopViewToRightAnimated(true);
            }
            else if (ECSlidingViewControllerTopViewPosition.Centered == pos && slidingController.UnderRightViewController != null && !movingRight)
            {
                slidingController.AnchorTopViewToLeftAnimated(true);
            }
            else if (ECSlidingViewControllerTopViewPosition.AnchoredLeft == pos || ECSlidingViewControllerTopViewPosition.AnchoredRight == pos)
            {
                slidingController.ResetTopViewAnimated(true);
            }
            else
            {
                _interactive = false;
            }
        }
        internal void PanEnded(SlidingViewController slidingController, UIView topView, float translationX, float velocityX)
        {
            if (!_interactive)
            {
                return;
            }

            _panningRight = velocityX > 0;
            _interactive  = false;

            // Update gravity direction
            this.Gravity.GravityDirection = _panningRight ? new CGVector(2f, 0f) : new CGVector(-2f, 0f);
            // Update push behavior
            this.Push.Angle     = 0;
            this.Push.Magnitude = velocityX;
            this.Push.Active    = true;
            // Add composite behavior
            this.Animator.AddBehavior(this.Composite);
        }
        internal void PanEnded(SlidingViewController slidingController, UIView topView, float translationX, float velocityX)
        {
            if (!_interactive) return;

            _panningRight = velocityX > 0;
            _interactive  = false;

            // Update gravity direction
            this.Gravity.GravityDirection = _panningRight ? new CGVector(2f, 0f) : new CGVector(-2f, 0f);
            // Update push behavior
            this.Push.Angle     = 0;
            this.Push.Magnitude = velocityX;
            this.Push.Active    = true;
            // Add composite behavior
            this.Animator.AddBehavior(this.Composite);
        }
        internal void PanChanged(SlidingViewController slidingController, UIView topView, float translationX, float velocityX)
        {
            if (!_interactive) return;

            RectangleF initialFrame = _initialTopViewFrame;
            float      newLeftEdge  = initialFrame.X + translationX;
            // Calculate left edge
            if (newLeftEdge < 0)
            {
                newLeftEdge = 0;
            }
            else if (newLeftEdge > slidingController.AnchorRightRevealAmount)
            {
                newLeftEdge = slidingController.AnchorRightRevealAmount;
            }
            // Update top view frame
            initialFrame.X = newLeftEdge;
            topView.Frame  = initialFrame;
            // Update transition
            float percentComplete = ((!_positiveLeftToRight ? translationX * -1f : translationX) / _fullWidth);
            percentComplete = percentComplete < 0   ? 0   : percentComplete;
            percentComplete = percentComplete > 100 ? 100 : percentComplete;

            slidingController.UpdateInteractiveTransition(percentComplete);
        }
        internal void PanBegan(SlidingViewController slidingController, UIView topView, float translationX, float velocityX)
        {
            bool movingRight     = velocityX > 0;
            _initialTopViewFrame = ((CALayer)topView.Layer.PresentationLayer).Frame;
            _interactive         = true;

            ECSlidingViewControllerTopViewPosition pos = slidingController.CurrentTopViewPosition;

            // Move sliding panel
            if (ECSlidingViewControllerTopViewPosition.Centered == pos && slidingController.UnderLeftViewController != null && movingRight)
            {
                slidingController.AnchorTopViewToRightAnimated (true);
            }
            else if (ECSlidingViewControllerTopViewPosition.Centered == pos && slidingController.UnderRightViewController != null && !movingRight)
            {
                slidingController.AnchorTopViewToLeftAnimated (true);
            }
            else if (ECSlidingViewControllerTopViewPosition.AnchoredLeft == pos || ECSlidingViewControllerTopViewPosition.AnchoredRight == pos)
            {
                slidingController.ResetTopViewAnimated(true);
            }
            else
            {
                _interactive = false;
            }
        }
        public override void AnimateTransition(IUIViewControllerContextTransitioning transitionCtx)
        {
            SlidingViewController sliding = this.SlidingViewController;
            // Get constant from uikit
            IntPtr   handle = Dlfcn.dlopen(MonoTouch.Constants.UIKitLibrary, 0);
            NSString UITransitionContextToViewControllerKey = Dlfcn.GetStringConstant(handle, "UITransitionContextToViewControllerKey");

            Dlfcn.dlclose(handle);
            // Get controllers
            UIViewController topController       = sliding.GetViewControllerForKey(ECSlidingViewController.ECTransitionContextTopViewControllerKey);
            UIViewController toController        = sliding.GetViewControllerForKey(UITransitionContextToViewControllerKey);
            RectangleF       topViewInitialFrame = sliding.GetInitialFrameForViewController(topController);
            RectangleF       topViewFinalFrame   = sliding.GetFinalFrameForViewController(topController);

            // Update top view frame
            topController.View.Frame = topViewInitialFrame;
            // Reset layer transforms
            CATransform3D transform = CATransform3D.Identity;

            transform.m34 = -0.002f;
            sliding.ContainerView.Layer.SublayerTransform = transform;

            UIViewController underController;
            float            revealWidth = 0f;
            bool             resetting   = false;

            if (topController == toController)
            {
                underController = sliding.GetViewControllerForKey(ECSlidingViewController.ECTransitionContextUnderLeftControllerKey);
                revealWidth     = sliding.GetInitialFrameForViewController(topController).X;
                resetting       = true;
            }
            else
            {
                underController = sliding.GetViewControllerForKey(UITransitionContextToViewControllerKey);
                revealWidth     = sliding.GetFinalFrameForViewController(topController).X;
                resetting       = false;
            }

            RectangleF underViewInitialFrame = sliding.GetInitialFrameForViewController(underController);
            RectangleF underViewFinalFrame   = sliding.GetFinalFrameForViewController(underController);

            underController.View.Frame = underViewInitialFrame.IsEmpty ? underViewFinalFrame : underViewInitialFrame;
            underController.View.RemoveFromSuperview();

            float      underViewHalfwayPoint = revealWidth / 2;
            RectangleF leftSideFrame         = new RectangleF(0, 0, underViewHalfwayPoint, underController.View.Bounds.Height);
            RectangleF rightSideFrame        = new RectangleF(underViewHalfwayPoint, 0, underViewHalfwayPoint, underController.View.Bounds.Height);

            UIView leftSideView  = underController.View.ResizableSnapshotView(leftSideFrame, true, UIEdgeInsets.Zero);
            UIView rightSideView = underController.View.ResizableSnapshotView(rightSideFrame, true, UIEdgeInsets.Zero);

            leftSideView.Layer.AnchorPoint = new PointF(0f, 0.5f);
            leftSideView.Frame             = leftSideFrame;

            rightSideView.Layer.Frame       = rightSideFrame;
            rightSideView.Layer.AnchorPoint = new PointF(1F, 0F);

            if (resetting)
            {
                this.UnfoldLayers(leftSideView.Layer, rightSideView.Layer);
            }
            else
            {
                this.FoldLayers(leftSideView.Layer, rightSideView.Layer);
            }

            sliding.ContainerView.Layer.InsertSublayerBelow(leftSideView.Layer, topController.View.Layer);
            sliding.ContainerView.Layer.InsertSublayerBelow(rightSideView.Layer, topController.View.Layer);

            // Animate panel
            UIView.Animate(
                this.TransitionDuration(transitionCtx),
                new NSAction(
                    delegate()
            {
                UIView.SetAnimationCurve(UIViewAnimationCurve.Linear);
                if (this.CoordinatorAnimations != null)
                {
                    this.CoordinatorAnimations(transitionCtx);
                }
                topController.View.Frame = topViewFinalFrame;

                if (resetting)
                {
                    this.FoldLayers(leftSideView.Layer, rightSideView.Layer);
                }
                else
                {
                    this.UnfoldLayers(leftSideView.Layer, rightSideView.Layer);
                }
            }
                    ),
                new NSAction(
                    delegate()
            {
                sliding.ContainerView.Layer.SublayerTransform = CATransform3D.Identity;
                leftSideView.RemoveFromSuperview();
                rightSideView.RemoveFromSuperview();

                bool topViewReset        = (resetting && !sliding.TransitionWasCancelled) || (!resetting && sliding.TransitionWasCancelled);
                topController.View.Frame = sliding.TransitionWasCancelled ? sliding.GetInitialFrameForViewController(topController) : sliding.GetFinalFrameForViewController(topController);

                if (topViewReset)
                {
                    underController.View.RemoveFromSuperview();
                }
                else
                {
                    underController.View.Frame = sliding.TransitionWasCancelled ? sliding.GetInitialFrameForViewController(underController) : sliding.GetFinalFrameForViewController(underController);
                    sliding.ContainerView.InsertSubviewBelow(underController.View, topController.View);
                }

                if (this.CoordinatorCompletion != null)
                {
                    this.CoordinatorCompletion(transitionCtx);
                }
                sliding.CompleteTransition(true);
            }
                    )
                );
        }