在新浪微博的首页部分,点击用户名会向下弹出一个表格,如下图:
我用模态弹出视图,但是系统的效果是从下往上弹出的,所以我们需要通过自定义转场动画,来达到我们想要的效果.详细效果大家可以打开新浪微博试试哦(ps:我的新浪微博ID是:U小姐咯.四个字哦,如图所示,欢迎关注😄).
1⃣️.为了简洁代码,我们用xib搭配,首先创建一个
PopViewController
并在xib拖入黑色带箭头的图片,并放上表格,进行一下适配.2⃣️.接下来自定义一个
DMPresentationController
继承于UIPresentationController
,代码如下
class DMPresentationController: UIPresentationController {
//如果不自定义转场,modal出来的控制器会移除原有的控制器,自定义的则不会
//自定义可以改变控制器的尺寸和屏幕不一样
var presentFrame = CGRectZero
override init(presentedViewController : UIViewController,presentingViewController : UIViewController) {
super.init(presentedViewController: presentedViewController, presentingViewController: presentingViewController)
}
//用于布局转场动画弹出的控件
override func containerViewWillLayoutSubviews() {
//这个属性是容器,所有弹出的的视图都是放在这里面的
// containerView
// presentedView() 通过方法拿到弹出视图
presentedView()?.frame = presentFrame
//添加蒙版,点击btn让图层收起来
// containerView?.addSubview(coverBtn)
//0代表最底层
containerView?.insertSubview(coverBtn, atIndex: 0)
coverBtn.addTarget(self, action: #selector(DMPresentationController.touch), forControlEvents: UIControlEvents.TouchUpInside)
}
func touch(){
presentedViewController.dismissViewControllerAnimated(true, completion: nil)
}
//MARK:懒加载
private var coverBtn : UIButton = {
let btn = UIButton.init(type: UIButtonType.Custom)
btn.frame = UIScreen.mainScreen().bounds
return btn
}()
}
3⃣️.我们自定义了转场动画,还需要一个负责转场动画的对象,创建DMPresentationManager
继承NSObject
,管理我们需要的效果.代码如下:
class DMPresentationManager: NSObject,UIViewControllerTransitioningDelegate,UIViewControllerAnimatedTransitioning {
var managerFrame = CGRectZero
private var isPresent = false
//该方法返回一个负责转场动画的对象
//可以在该对象中控制弹出视图的尺寸
func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController? {
let presentVc = DMPresentationController.init(presentedViewController: presented, presentingViewController: presenting)
presentVc.presentFrame = managerFrame
return presentVc
}
//该方法用于返回一个负责转场如何出现的对象
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning?{
//遵守协议,消失就会调用
isPresent = !isPresent
//发送通知,通知状态发生改变
NSNotificationCenter.defaultCenter().postNotificationName(DMPresentationManagerPresented, object: self)
return self
}
//用于返回一个负责转场如何消失的对象
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning?{
isPresent = !isPresent
NSNotificationCenter.defaultCenter().postNotificationName(DMPresentationManagerDismissed, object: self)
return self
}
//MARK:UIViewControllerAnimatedTransitioning
//告诉系统展现和小时的动画时长
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval{
//这个方法设置执行动画的时间
return 0.3
}
//用于管理modal如何展现和消失,都会调用这个方法
//只要实现了这个代理方法,系统就不会添加默认的动画,所有动画操作需要自己实现,包括需要展现的视图也需要自己添加到容器视图上(containerView)
//transitionContext,所有动画都保存在上下文中,就是可以通过transitionContext获取我们想要的东西
func animateTransition(transitionContext: UIViewControllerContextTransitioning){
//展现或者消失都会调用这个方法
if isPresent {
//获取需要弹出视图
//UITransitionContextFromViewKey, and UITransitionContextToViewKey
presentAnimation(transitionContext)
}else{
dismissedAnimation(transitionContext)
}
}
private func presentAnimation(transitionContext: UIViewControllerContextTransitioning){
guard let toView = transitionContext.viewForKey(UITransitionContextToViewKey) else{
return
}
//将需要弹出视图添加到containerView上
transitionContext.containerView()?.addSubview(toView)
//执行动画
toView.transform = CGAffineTransformMakeScale(1.0, 0.0)
//设置锚点
toView.layer.anchorPoint = CGPoint(x: 0.5,y: 0)
UIView.animateWithDuration(0.3, animations: { () ->Void in
toView.transform = CGAffineTransformIdentity
}) { (_)-> Void in //下划线代表忽略这个值
//自定义转场动画,执行完之后一定要告诉系统动画执行完毕了
transitionContext.completeTransition(true)
}
}
private func dismissedAnimation(transitionContext: UIViewControllerContextTransitioning){
guard let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey) else{
return
}
UIView.animateWithDuration(1, animations: { () ->Void in
fromView.transform = CGAffineTransformMakeScale(1.0, 0.000000)
}) { (_)-> Void in //下划线代表忽略这个值
//自定义转场动画,执行完之后一定要告诉系统动画执行完毕了
transitionContext.completeTransition(true)
}
}
}
4⃣️.接下来我们实现点击按钮可以弹出我们自定义的视图
let popVc = PopViewController()
//自定义转场动画
//设置代理
popVc.transitioningDelegate = animationManager
//设置样式
popVc.modalPresentationStyle = UIModalPresentationStyle.Custom
presentViewController(popVc, animated: true, completion: nil)
//MARK:懒加载
lazy var animationManager :DMPresentationManager = {
let manager = DMPresentationManager()
//这里我们对需要弹出视图的frame进行相应的设置
manager.managerFrame = CGRectMake(100, 60, 200, 320)
return manager
}()
以上😄