代码地址如下:
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大师代发,拒绝转载,转载需要作者授权

KINavigationController使用演示例子的更多相关文章

  1. 三层架构的OPP实现的演示例子

    例子:演示会员添加与删除 说明:因为是简单的例子,我们用在屏幕上打印"添加成功"和"删除成功"这几个字表示会员的添加与删除,仅仅为了演示如何实现三层的分离: 1 ...

  2. 百度webuploader 上传演示例子

    前端代码 <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="baiduWebU ...

  3. 实例演示Android异步加载图片

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

  4. 实例演示Android异步加载图片(转)

    本文给大家演示异步加载图片的分析过程.让大家了解异步加载图片的好处,以及如何更新UI.首先给出main.xml布局文件:简单来说就是 LinearLayout 布局,其下放了2个TextView和5个 ...

  5. Web三维技术:Flash Builder+away3d平台搭建(含演示视频)

    转自:http://www.cnblogs.com/beer/archive/2011/07/08/2101492.html 前言:作为页面中实验设备的显示层,需要一个swf作为显示的UI.虽然可以用 ...

  6. 5、Cocos2dx 3.0小游戏开发的例子寻找测试三个简单的介绍和总结

    繁重的劳动开发商,当转载请注明出处:http://blog.csdn.net/haomengzhu/article/details/27186557 測试例子简单介绍 Cocos2d-x 为我们提供了 ...

  7. 转 UNIGUI安装教程、使用例子

    转 UNIGUI安装教程.使用例子 http://my.oschina.net/u/582827/blog/203429?p={{currentPage-1}} 转 uniGui安装教程.使用例子 发 ...

  8. 5、Cocos2dx 3.0游戏开发找小三之測试例子简单介绍及小结

    重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27186557 測试例子简单介绍 Cocos2d-x ...

  9. 微服务+DDD代码结构例子

    这是一个基本的微服务+DDD演示例子: 基于 Spring Boot 1.5.6 , Spring Cloud Edgware.SR4 Version 微服务 + DDD,个人觉得应该是首先是从微服务 ...

随机推荐

  1. Delphi读写二进制文件

    http://www.cnblogs.com/hnxxcxg/p/3691742.html 二进制文件(也叫类型文件),二进制文件是由一批同一类型的数据组成的一个数据序列,就是说一个具体的二进制文件只 ...

  2. zabbix获取到的数值自定义单位

    1) 查找php文件 # find / -name "func.inc.php" /usr/share/zabbix/include/func.inc.php 2)修改文件 #vi ...

  3. scrapy xpath 从response中获取li,然后再获取li中img的src

    lis = response.xpath("//ul/li") for li in lis: src = li.xpath("img/@src") # 如果xp ...

  4. hdu6230

    hdu6230 题意 给出一个字符串,问有多少个子串 \(S[1..3n-2](n \geq 2)\) 满足 \(S[i]=S[2n-i]=S[2n+i-2] (1\leq i \leq n)\) . ...

  5. CodeForces - 990G GCD Counting

    Discription You are given a tree consisting of nn vertices. A number is written on each vertex; the ...

  6. 【旋转卡壳】poj3608 Bridge Across Islands

    给你俩凸包,问你它们的最短距离. 咋做就不讲了,经典题,网上一片题解. 把凸包上的点逆时针排序.可以取它们的平均点,然后作极角排序. 旋转卡壳其实是个很模板化的东西…… 先初始化分别在凸包P和Q上取哪 ...

  7. 【最短路】【spfa】【最小割】【Dinic】bzoj1266 [AHOI2006]上学路线route

    原问题等价于断掉一些边,让原来所有的最短路全都无法联通S和T. 先求最短路,然后把在最短路上的边(dis[u[i]]+w[i]==dis[v[i]])加入新图里,跑最小割.显然. 注意是无向图. #i ...

  8. 1.1(java学习笔记) 面向过程与面向对象

    面向过程思考时,我们会先思考具体的步骤,第一步走什么,第二步做什么. 比如电脑新建文件夹,第一步:打开电脑 第二步:按下鼠标右键. 第三步:找到新建选项 第四步:点击新建选项下的文件夹 c语言是典型的 ...

  9. Problem G: 零起点学算法27——等级分制度

    #include<stdio.h> int main() { int a,b; while(scanf("%d %d",&a,&b)!=EOF) +a* ...

  10. Delphi制作软键盘

        { 作者: han 日期: 2006.06.02 } unit softkey; interface uses Windows, Messages, SysUtils, Variants, C ...