在实际开发中经常会出现的效果图 :
如何实现这种效果呢?
下面直接上代码
```objc
//设置转场动画的代理
menu.transitioningDelegate=delegateOftransition
//设置转场动画的样式为自定义
menu.modalPresentationStyle=UIModalPresentationStyle.Custom
//执行modal动画
self.presentViewController(menu, animated:true, completion:nil)
```
当然,成为了代理还要实现代理方法,下面就是代理里面的代码
```objc
extensiontransitionDelegate:UIViewControllerTransitioningDelegate{
//此方法返回一个用于负责转场动画的对象
funcpresentationControllerForPresentedViewController(presented:UIViewController, presentingViewController presenting:UIViewController, sourceViewController source:UIViewController) ->UIPresentationController?
{
letpresentation =WLCPresentation(presentedViewController: presented, presentingViewController:presenting)
presentation.showViewFrame=menuFrame
returnpresentation
}
//返回一个控制出现转场动画的对象
funcanimationControllerForPresentedController(presented:UIViewController, presentingController presenting:UIViewController, sourceController source:UIViewController) ->UIViewControllerAnimatedTransitioning?
{
isPresent=true//菜单要显示,赋值为true
returnself
}
//返回一个控制消失转场动画的对象
funcanimationControllerForDismissedController(dismissed:UIViewController) ->UIViewControllerAnimatedTransitioning?
{
isPresent=false//菜单要消失,赋值为false
returnself
}
```
注意第一个函数返回的对象,这个对象是需要自定义的,并且继承于UIPresentationController,这样就可以在这个对象里面实现控制弹出的控制器的view的大小了,下面就是自定义的对象中的代码了
```objc
overridefunccontainerViewWillLayoutSubviews() {
//设置弹出视图的尺寸
presentedView()?.frame.size = CGSize(width: 200, height: 200)
presentedView()?.center.x = UIScreen.mainScreen().bounds.size.width * 0.5
presentedView()?.frame.origin.y = 50
//添加返回蒙板按钮
//containerView非常重要,容器视图,所有modal出来的视图都是添加到containerView上面的
containerView?.insertSubview(bgBtn, atIndex:0)
bgBtn.addTarget(self, action:Selector("dismissClick"), forControlEvents:UIControlEvents.TouchUpInside)
}
lazyvarbgBtn :UIButton= {
letbgBtn =UIButton()
bgBtn.frame=UIScreen.mainScreen().bounds
bgBtn.backgroundColor=UIColor.clearColor()
returnbgBtn
}()
funcdismissClick(){
//presentedViewController非常重要,已经modal出来的控制器
presentedViewController.dismissViewControllerAnimated(true, completion:nil)
}
}
```
我还在modal出来的控制器上加了一个等于屏幕尺寸的按钮,这样只要点击view以外任何一个地方就可以dismiss掉这个控制器。
现在继续回到delegateOftransition这个代理中,可以看到它还实现了另外两个代理方法,返回对象均为其本身,这意味着它还要遵守UIViewControllerAnimatedTransitioning这个协议,然后实现协议中的方法,下面是代码
```objc
extensiontransitionDelegate:UIViewControllerAnimatedTransitioning
{
//用于控制动画的时长
functransitionDuration(transitionContext:UIViewControllerContextTransitioning?) ->NSTimeInterval
{
return 1.0;
}
//专门用于管理modal如何展现和消失的,无论是展现还是消失都会调用该方法
/*
注意点:只要我们实现了这个方法,那么系统就不会再有默认的动画了
也就是说默认的modal动画不会再帮我们添加了,所有的动画操作都要我们自己实现,包括需要展现的视图也要手动进行添加到容器视图(containerView)上了
*/
funcanimateTransition(transitionContext:UIViewControllerContextTransitioning)
{
ifisPresent{
presentMenu(transitionContext)
}else{
dismissMenu(transitionContext)
}
}
/**
展现菜单函数
*/
funcpresentMenu(transitionContext:UIViewControllerContextTransitioning){
//按钮是选中状态,需要显示菜单
//1.拿到需要添加的视图
lettoView = transitionContext.viewForKey(UITransitionContextToViewKey)
//2.将需要添加的视图添加到容器视图(containerView)上
transitionContext.containerView()?.addSubview(toView!)
//3.设置动画
toView?.transform=CGAffineTransformMakeScale(1.0,0.0)
toView?.layer.anchorPoint=CGPointMake(0.5,0)
UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () ->Voidin
toView?.transform=CGAffineTransformIdentity
}) { (_) ->Voidin
//注意:自定义的转场动画,在动画执行完毕后一定要告诉系统动画执行完毕
transitionContext.completeTransition(true)
}
}
/**
*隐藏菜单函数
*/
funcdismissMenu(transitionContext:UIViewControllerContextTransitioning){
//1.拿到需要隐藏的视图
letfromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
//2.执行隐藏的动画
UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () ->Voidin
fromView?.transform=CGAffineTransformMakeScale(1.0,0.00001)
}, completion: { (_) ->Voidin
//注意:自定义的转场动画,在动画执行完毕后一定要告诉系统动画执行完毕
transitionContext.completeTransition(true)
})
}
```
总结一下,具体实现步骤就是设置转场动画的代理,然后在实现代理方法中,需要自定义一个继承自UIPresentationController的类,这个类里面可以控制modal出来的控制器的尺寸和布局子控件等,最后在转场动画的代理中可以设置动画的样式。