UIViewController自定义过渡样式(由内向外呈现)

时间:2017-02-16 20:15:23

标签: ios iphone xcode ipad xamarin.ios

我想制作一个自定义演示文稿(推送或模态)以在"内部显示"内部显示视图控制器。我四处搜索,但大多数方法是从不同的方向(从右边,从上面)呈现视图控制器而不是默认方向,但我需要的是包括在viewController中缩放缩放的内容,如果有任何解决方案的话该..

1 个答案:

答案 0 :(得分:0)

您可以实施自己的自定义UIViewControllerAnimatedTransitioning。这是C#中自定义圆圈渐变(内向外)过渡的示例(不应该很难在swift中重现):

/// <summary>
/// Circle fade transition animator.
/// </summary>
public class CircleFadeTransitionAnimator : UIViewControllerAnimatedTransitioning
{
    public bool IsPresentation = true;
    nfloat screenHeight = UIScreen.MainScreen.Bounds.Height;
    nfloat screenWidth = UIScreen.MainScreen.Bounds.Width;

    public override void AnimateTransition(IUIViewControllerContextTransitioning transitionContext)
    {
        //The current view controller
        var fromVC = transitionContext.GetViewControllerForKey(UITransitionContext.FromViewControllerKey);
        var fromView = fromVC.View;

        //The view controller we wish to present to the user
        var toVC = transitionContext.GetViewControllerForKey(UITransitionContext.ToViewControllerKey);
        var toView = toVC.View;

        // Set up some variables for the animation.
        var containerView = transitionContext.ContainerView;

        // Always add the "to" view to the container.
        // And it doesn't hurt to set its start frame.
        containerView.AddSubview(toView);

        // Creates two circular UIBezierPath instances; one is the size of the button, and the second has a radius
        // large enough to cover the entire screen. The final animation will be between these two bezier paths.
        CGSize size;
        if (fromVC is LogInViewController)
            size = new CGSize(5, 5);
        else
            size = new CGSize(screenWidth * 0.65, screenWidth * 0.65);

        var startingRect = new CGRect(screenWidth / 2 - size.Width/2, screenHeight / 2 - size.Height/2, size.Width, size.Height);
        var circleMaskPathInitial = UIBezierPath.FromOval(startingRect);
        var extremePoint = new CGPoint(screenWidth / 2, screenHeight / 2 - toView.Bounds.Height);
        var radius = (nfloat) Math.Sqrt((extremePoint.X * extremePoint.X) + (extremePoint.Y * extremePoint.Y));
        var circleMaskPathFinal = UIBezierPath.FromOval(startingRect.Inset(-radius, -radius));

        // Creates a new CAShapeLayer to represent the circle mask. Assign its path value with the final circular path 
        // after the animation to avoid the layer snapping back after the animation completes.
        var maskLayer = new CAShapeLayer();
        maskLayer.Path = circleMaskPathFinal.CGPath;
        toVC.View.Layer.Mask = maskLayer;

        // Creates a CABasicAnimation on the path key path that goes from circleMaskPathInitial to circleMaskPathFinal. 
        var maskLayerAnimation = CABasicAnimation.FromKeyPath("path");
        maskLayerAnimation.SetFrom(circleMaskPathInitial.CGPath);
        maskLayerAnimation.SetTo(circleMaskPathFinal.CGPath);
        maskLayerAnimation.Duration = TransitionDuration(transitionContext);
        maskLayerAnimation.Delegate = new CircleAnimationDelegate(transitionContext);
        maskLayer.AddAnimation(maskLayerAnimation, "path");
    }

    /// <summary>
    /// How long will the transition last?
    /// </summary>
    /// <returns>The duration.</returns>
    /// <param name="transitionContext">Transition context.</param>
    public override double TransitionDuration(IUIViewControllerContextTransitioning transitionContext)
    {
        return 0.3;
    }
}

您还需要实现自己的CAAnimationDelegate,如下所示:

/// <summary>
/// Circle animation delegate.
/// </summary>
class CircleAnimationDelegate : CAAnimationDelegate
{
    IUIViewControllerContextTransitioning transitionContext;
    //UIView toView;

    /// <summary>
    /// Initializes a new instance of the <see cref="T:Plimes.CircleAnimationDelegate"/> class.
    /// </summary>
    /// <param name="transitionContext">Transition context.</param>
    public CircleAnimationDelegate(IUIViewControllerContextTransitioning transitionContext)
    {
        this.transitionContext = transitionContext;
        //this.toView = toView;
    }

    /// <summary>
    /// On Animations stopped.
    /// </summary>
    /// <param name="anim">Animation.</param>
    /// <param name="finished">If set to <c>true</c> finished.</param>
    public override void AnimationStopped(CAAnimation anim, bool finished)
    {
        transitionContext.CompleteTransition(!transitionContext.TransitionWasCancelled);
        transitionContext.GetViewControllerForKey(UITransitionContext.ToViewControllerKey).View.Layer.Mask = null;
        transitionContext.GetViewControllerForKey(UITransitionContext.FromViewControllerKey).View.Layer.Mask = null;
        //toView.RemoveFromSuperview();
    }
}

然后你可以继承你的UINavigationController并覆盖它的GetAnimationControllerForOperation()委托方法,如下所示:

/// <summary>
/// Navigation controller subclass for assigning custom delegate.
/// </summary>
public partial class NavigationController : UINavigationController
{
    /// <summary>
    /// Initializes a new instance of the <see cref="T:Plimes.NavigationController"/> class.
    /// </summary>
    /// <param name="handle">Handle.</param>
    public NavigationController (IntPtr handle) : base (handle)
    {
        Delegate = new NavigationControllerDelegate();
    }
}

/// <summary>
/// Navigation controller delegate for custom transition animations.
/// </summary>
public class NavigationControllerDelegate : UINavigationControllerDelegate 
{ 
    /// <summary>
    /// Gets the animation controller for operation.
    /// </summary>
    /// <returns>The animation controller for operation.</returns>
    /// <param name="navigationController">Navigation controller.</param>
    /// <param name="operation">Operation.</param>
    /// <param name="fromViewController">From view controller.</param>
    /// <param name="toViewController">To view controller.</param>
    public override IUIViewControllerAnimatedTransitioning GetAnimationControllerForOperation(UINavigationController navigationController, UINavigationControllerOperation operation, UIViewController fromViewController, UIViewController toViewController)
    {
        // If left-right transition is needed
        if (operation == UINavigationControllerOperation.Push)
        {
            var animator = new CircleFadeTransitionAnimator();
            animator.IsPresentation = true;
            return animator;
        }
    }   
}

希望这会有所帮助!