代码地址如下:
http://www.demodashi.com/demo/12905.html

运行效果

实现思路

创建pan手势,添加到页面中,监听手势的动作。重写push的方法,在push之前截图保存到数组。重写pop的方法,在pop之前删除截图。pop的动画效果是利用截图的image添加到topView上,从视觉效果上实现缩放、平移的动画效果。以下是具体的实现思路:

1.创建Pan手势识别器

 delegate = self
let panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(paningGestureReceive(recoginzer:)))
panRecognizer.delegate = self
view.addGestureRecognizer(panRecognizer)
//实现侧滑返回
interactivePopGestureRecognizer?.delegate = self

2.实现手势的相应事件

//MARK: - Events
@objc func paningGestureReceive(recoginzer:UIPanGestureRecognizer) {
//如果只有一个控制器或者不允许全屏返回,return
if self.viewControllers.count <= 1 || !canDragBack {
return
} let touchPoint = recoginzer.location(in: UIApplication.shared.keyWindow) switch recoginzer.state {
case .began:
isMoving = true
startTouch = touchPoint
if backgroundView == nil {
let frame = TOP_VIEW?.frame
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
TOP_VIEW?.superview?.insertSubview(backgroundView!, belowSubview: TOP_VIEW!) blackMask = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
blackMask?.backgroundColor = UIColor.black
backgroundView?.addSubview(blackMask!)
}
backgroundView?.isHidden = false
if lastScreenShotView != nil {
lastScreenShotView?.removeFromSuperview()
} let lastScreenShot = screenShotsList.lastObject as! UIImage
lastScreenShotView = UIImageView(image: lastScreenShot)
backgroundView?.insertSubview(lastScreenShotView!, belowSubview: blackMask!) break
case .ended:
//手势结束,判断是返回还是回到原位
if touchPoint.x - (startTouch?.x)! > 50 {
UIView.animate(withDuration: 0.3, animations: {
self.moveView(withX: self.kMAXWidth)
}, completion: { (finished:Bool) in
self.popViewController(animated: false)
var frame = self.TOP_VIEW?.frame
frame?.origin.x = 0
self.TOP_VIEW?.frame = frame!
self.isMoving = false
self.backgroundView?.isHidden = true
// End paning,remove last screen shot
self.customAnimation.removeLastScreenShot()
})
} else {
UIView.animate(withDuration: 0.3, animations: {
self.moveView(withX: 0)
}, completion: { (finished:Bool) in
self.isMoving = false
self.backgroundView?.isHidden = true
})
}
return //直接返回,不在往下执行
case .cancelled:
UIView.animate(withDuration: 0.3, animations: {
self.moveView(withX: 0)
}, completion: { (finished:Bool) in
self.isMoving = false
self.backgroundView?.isHidden = true
})
return
default:
break
}
if isMoving! {
self.moveView(withX: touchPoint.x - (startTouch?.x)!)
}
}

3.创建截图需要的backgroundView和作为遮罩的blackMask,存放截图所需的数组

if backgroundView == nil {
let frame = TOP_VIEW?.frame
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
TOP_VIEW?.superview?.insertSubview(backgroundView!, belowSubview: TOP_VIEW!) blackMask = UIView(frame: CGRect(x: 0, y: 0, width: (frame?.size.width)!, height: (frame?.size.height)!))
blackMask?.backgroundColor = UIColor.black
backgroundView?.addSubview(blackMask!)
}
backgroundView?.isHidden = false
if lastScreenShotView != nil {
lastScreenShotView?.removeFromSuperview()
} let lastScreenShot = screenShotsList.lastObject as! UIImage
lastScreenShotView = UIImageView(image: lastScreenShot)
backgroundView?.insertSubview(lastScreenShotView!, belowSubview: blackMask!)

4.在push前截图,并保存

override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if self.viewControllers.count >= 1 {
let screenshot = getScreenshot()
if screenshot != nil {
screenShotsList.add(screenshot!)
}
}
super.pushViewController(viewController, animated: animated)
}

5.重写常用的pop方法,在pop前删除相应的截图

@discardableResult
override func popViewController(animated: Bool) -> UIViewController? {
screenShotsList.removeLastObject()
return super.popViewController(animated: animated)
} override func popToViewController(_ viewController: UIViewController, animated: Bool) -> [UIViewController]? {
var removeCount = 0
for i in stride(from: viewControllers.count-1, to: 0, by: -1) {
if viewController == viewControllers[i] {
break
}
screenShotsList.removeLastObject()
removeCount = removeCount+1
}
customAnimation.removeCount = removeCount
return super.popToViewController(viewController, animated: animated)
} override func popToRootViewController(animated: Bool) -> [UIViewController]? {
screenShotsList.removeAllObjects()
customAnimation.removeAllScreenShot()
return super.popToRootViewController(animated: animated)
}

到此处能实现手势整体返回的效果,要实现点击返回按钮也能整体返回,需要自定义返回动画。实现协议UIViewControllerAnimatedTransitioning

6.让navigationController遵守UINavigationControllerDelegate实现下面的方法,在方法里面可根据operation判断需要自定义的类型(pop/push)

 func navigationController(_ navigationController: UINavigationController,
animationControllerFor operation: UINavigationControllerOperation,
from fromVC: UIViewController,
to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning?

7.使用一个类实现UIViewControllerAnimatedTransitioning协议

func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval

//定义动画
func animateTransition(using transitionContext: UIViewControllerContextTransitioning)

项目结构图

KINavigationController使用演示例子

代码地址如下:
http://www.demodashi.com/demo/12905.html

注:本文著作权归作者,由demo大师代发,拒绝转载,转载需要作者授权

最新文章

  1. C#操作Dataset数据集与SQLite数据库
  2. GDUT 校赛02 dp回文串
  3. audio.js – 随时随地,播放 HTML5 的声音
  4. Ubuntu 14.04安装OpenCV 3.1
  5. 常用上传shell脚本
  6. RTSP,RTP,RTCP的区别
  7. 谱聚类(Spectral Clustering)详解
  8. 用VS Code体验调试.NET Core 2.0 Preview (传统三层架构)
  9. 工厂参观记:.NET Core 中 HttpClientFactory 如何解决 HttpClient 臭名昭著的问题
  10. Redis常用操作--------SortedSet(有序集合)
  11. 生成更大的陆地 Making A Large Island
  12. Python数据分析库pandas基本操作
  13. Python学习笔记第五周
  14. 【转载】 深度强化学习处理cartpole为什么reward很难超过200?
  15. 收集的dubbo博客
  16. TypeScript 之 声明文件的发布
  17. arm irq system
  18. 我们为什么要使用Spring Cloud?简介
  19. mybatis中使用where in查询时的注意事项
  20. Gradle Maven部署,转化

热门文章

  1. sublime text3下使用TAG快捷键ctrl+alt+f失效的解决方法
  2. 巧用nth_element求容器前n%大小的那个数
  3. python 如何放心干净的卸载模块
  4. Python爬链接
  5. 22、Django实战第22天:课程评论
  6. 通用数据库管理工具DBeaver
  7. [BZOJ 3233] 找硬币
  8. 【博弈论】【SG函数】poj2311 Cutting Game
  9. [USACO2015DEC]Max Flow
  10. 检测密码 Exercise06_18