UIViewController 自定义过渡风格(由内而外呈现)
Posted
技术标签:
【中文标题】UIViewController 自定义过渡风格(由内而外呈现)【英文标题】:UIViewController custom transition style (inside out presentation) 【发布时间】:2017-02-16 20:15:22 【问题描述】:我想制作一个自定义演示文稿(推送或模态)以在我搜索的“由内而外的演示文稿”中显示视图控制器,但大多数方法是从不同的方向(从右,从上)呈现视图控制器默认方向,但如果有任何解决方案,我需要的是包括在 viewController 中缩放缩放的东西..
【问题讨论】:
“由内而外的演示文稿”?你将不得不解释你在说什么。 你看我的回答了吗?它应该可以解决您的问题! 【参考方案1】:您可以实现自己的自定义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;
希望这会有所帮助!
【讨论】:
以上是关于UIViewController 自定义过渡风格(由内而外呈现)的主要内容,如果未能解决你的问题,请参考以下文章
从 Tableview 自定义单元格翻转过渡到 UIViewController
自定义 UIViewController 过渡动画适用于演示,但不适用于解雇
如何使用自定义 UIViewController 转换来实现这一点?