Swift4.1转场动画实现侧滑抽屉效果

论坛 期权论坛 脚本     
niminba   2021-5-23 03:43   1094   0

本文实现使用了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 shouldResponseRecognizer {
 self.updateAnimator(percentage)
 }
 default:
 if shouldResponseRecognizer {
 self.cancelAnimator(percentage, velocity: velocity)
 }
 }
 }
 
 @objc func panDrawerAction(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: false)
 }
 case .changed:
 if shouldResponseRecognizer {
 self.updateAnimator(percentage)
 }
 default:
 if shouldResponseRecognizer {
 self.cancelAnimator(percentage, velocity: velocity)
 }
 }
 }
 
 func beginAnimator(showDrawer: Bool) {
 self.animator?.interative = true
 if showDrawer {
 self.base?.transitioningDelegate = self.animator
 self.base?.present(self.drawer!, animated: true, completion: nil)
 }else {
 self.drawer?.transitioningDelegate = self.animator
 self.drawer?.dismiss(animated: true, completion: nil)
 }
 }
 
 func updateAnimator(_ percentage: CGFloat) {
 self.animator?.update(percentage)
 }
 
 func cancelAnimator(_ percentage: CGFloat, velocity: CGFloat) {
 if percentage < 0.3 && velocity < 300 {
 self.animator?.cancel()
 }else {
 self.animator?.finish()
 }
 }
 
}
//
// Animator.swift
// PratiseSwift
//
// Created by EugeneLaw on 2018/7/31.
// Copyright © 2018年 EugeneLaw. All rights reserved.
//
 
import UIKit
 
let DRAWER_ANIMATION_TIME = 0.3
 
class Animator: UIPercentDrivenInteractiveTransition, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning {
 
 /**是否交互转场*/
 var interative = false
 var showDrawer = false
 vU%	M4(聹4(4)4(2'JR#&/***":"fJ3*:"fj4("o:j:"V""b:"fJ3*:"fr"Gj惖/+:"k"f.:"fJ3"fj:""o*:"j^gG*+:"fjb"fOk:"fg>V4(4(Rj^g>r*:"jZW6>惖/"G*+2'Jr>s6W3vN7j^gR"fj6WR6W*:"f4(5|%	Qх
4)4(fkR"j>c<4(4(!(AM(4(
14(
Ё14(4(4)U%-(4(5I,胢)Ё%M耍U%M}
MQM锡
M锡U%M锤聙4)ЁA%M耍U%M}
MQM锡
M锡U%M锤聙4)ЁA%M耍U%M}
MQM锡
M锡U%M锤聙4)ЁA%M耍U%M}
MQM锡
M锡U%M锤聙4)Ё%}UMI}%9QI
}%%=4%U%4)Ё%}UMI}%9QI
}%%=4%U%4)ЁA`%M耍U%M}
MQM锡
M锡U%M锤聙4(4(5I,胞V3v4)ЁQ		I}!%!PA`)Ё9Y%Q%=9}!%!PA`4)M
I9}]%Q ЁЁM
I9}]%Q!}U94(4)M
I9}!%!PЁЁM
I9}!%!Q}U94(4(4)M
I9}]%Q!}U9
ЁU%M锹4)4)M
I9}!%!Q}U9
ЁU%M锹)4(5I,胦s&)Ё
=1=I}]!%QM5=-4(4(4(6s&6"AU%
(4(4)
MU%
4(4(%(%(%(ЁM%%t4(ЁM%%Хt4(ЁM%%t4(MM!4(M聝M!4(M聉M!4(Ё
СССС4()4(4(n*b4)MY|U%YU%

M锰аФ
((4(4)4(4(_nj4(4)|U%Y
Ёй4)4(4(r"njC4(4)`|U%Y
Ёй4(4(r"njC4(4)|U%Y
ЁйФ4)4(4(r"njC4(4)d|U%Y
Ёй4(4(r"njCc(4)|U%Y
ЁйСФ4)4(4(_njc(4)С|U%Y
Ёй)4(brZj3ro疒j惚r'&*rokkR2
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP