实现使用了Modal转场动画,原因是项目多由导航控制器和标签控制器作为基类,为了不影响导航控制器的代理,转场动画使用模态交互。
代码使用SnapKit进行布局,能够适应屏幕旋转。手势速率大于300或进度超过30%的时候直接完成动画,否则动画回滚取消,具体数值可以修改对应的常量。抽屉出现的时候,主控制有遮罩,对应关键字是mask。
实现文件只有两个
DrawerControl:控制抽屉出现,一行代码即可调用
Animator:负责动画实现,包括了交互式的代理事件和非交互式的代理事件
//
// DrawerControl.swift
// PratiseSwift
//
// Created by EugeneLaw on 2018/7/31.
// Copyright © 2018年 EugeneLaw. All rights reserved.
//
import UIKit
enum DrawerSize {
case Left
case Right
}
class DrawerControl: NSObject {
/**主页面*/
var base: UIViewController?
/**抽屉控制器*/
var drawer: UIViewController?
/**抽屉在左边还是右边,默认左边,没有实现右边,要右边自己去animator里面加判断*/
var whichSize = DrawerSize.Left
/**拖拽手势*/
var panBase: UIPanGestureRecognizer?
var panDrawer: UIPanGestureRecognizer?
/**主页面在抽屉显示时保留的宽度*/
var baseWidth: CGFloat {
get {
return self.animator!.baseWidth
}
set {
self.animator?.baseWidth = newValue
}
}
/**是否应该响应手势*/
var shouldResponseRecognizer = false
/**效果响应*/
var animator: Animator?
init(base: UIViewController, drawer: UIViewController) {
super.init()
self.base = base
self.drawer = drawer
animator = Animator(base: self.base!, drawer: self.drawer!)
self.panBase = UIPanGestureRecognizer(target: self, action: #selector(panBaseAction(pan:)))
base.view.addGestureRecognizer(self.panBase!)
self.panDrawer = UIPanGestureRecognizer(target: self, action: #selector(panDrawerAction(pan:)))
drawer.view.addGestureRecognizer(self.panDrawer!)
self.drawer?.transitioningDelegate = self.animator
}
deinit {
if self.panBase != nil {
self.base?.view.removeGestureRecognizer(self.panBase!)
self.panBase = nil
}
if self.panDrawer != nil {
self.drawer?.view.removeGestureRecognizer(self.panDrawer!)
self.panDrawer = nil
}
}
}
extension DrawerControl {
///显示抽屉
func show() {
if (self.base?.view.frame.origin.x)! > SCREEN_WIDTH/2 {
return
}
self.animator?.interative = false
self.base?.present(self.drawer!, animated: true, completion: nil)
}
///关闭抽屉,或直接dismiss即可
func close() {
self.animator?.interative = false
self.drawer?.dismiss(animated: true, completion: nil)
}
}
extension DrawerControl {
@objc func panBaseAction(pan: UIPanGestureRecognizer) {
let transition = pan.translation(in: self.drawer?.view)
let percentage = CGFloat(transition.x/SCREEN_WIDTH)
let velocity = CGFloat(fabs(pan.velocity(in: self.drawer?.view).x))
switch pan.state {
case .began:
if transition.x < 0 {
shouldResponseRecognizer = false
}else {
shouldResponseRecognizer = true
}
if shouldResponseRecognizer {
self.beginAnimator(showDrawer: true)
}
case .changed:
if shouldRes