Swift开发小技巧--自定义转场动画
自定义转场动画
- 个人理解为重写了被弹出控制器的modal样式,根据自己的样式来显示modal出来的控制器
例:presentViewController(aVC, animated: true, completion: nil)
1.为了实现如图,modal出来的aVC控制器有下图这样的效果
首先,需要在modal出来之前,设置aVC的自定义转场动画的样式为自定义(UIModalPresentationStyle.Custom)
其次,设置自定义转场动画的代理,协议
UIViewControllerTransitioningDelegate
(代理可以是当前控制器,项目中为了减少当前控制器的代码量,单独抽取了一个类)
// 2.创建菜单
let sb = UIStoryboard(name: "PopoverMenuViewController", bundle: nil)
let menuVC = (sb.instantiateInitialViewController())!
// 自定义转场动画
// 2.1设置自定义转场动画的样式
menuVC.modalPresentationStyle = UIModalPresentationStyle.Custom
// 2.2设置转场动画的代理
menuVC.transitioningDelegate = presentationMgr
// 3.弹出菜单,modal默认的弹出样式是从上往下,而且还不能控制弹出控制器的大小
presentViewController(menuVC, animated: true, completion: nil)
2.UIViewControllerTransitioningDelegate协议中的三个方法
- 方法一(返回一个负责转场动画的对象,转场动画完成后显示的尺寸和位置,可以在这个负责转场动画对象中设置,
所以说要自定义这个类,在自定义的负责转场动画的类中设置自己需要的位置和尺寸
) :
func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController?
{
// 自定义负责转场的对象ChaosPresentationController
let pc = ChaosPresentationController(presentedViewController: presented, presentingViewController: presenting)
// 位置由外界决定
pc.presentViewFrame = presentViewFrame
return pc
}
2.1自定义自定义负责转场的对象ChaosPresentationController : UIPresentationController,也就是自定义转场.作用:
1.如果不自定义转场,modal出来的控制器会移除原有的控制器
2.如果不自定义转场,modal出来的控制器不会移除原有的控制器
3.如果不自定义转场,modal出来的控制器的尺寸和屏幕一样
4.如果自定义转场,modal出来的控制器的尺寸可以在containerViewWillLayoutSubviews方法中控制
5.containerView 非常重要,容器试图,所有modal出来的视图都添加到了containerView上
6.presentedView() 非常重要,通过该方法能够拿到弹出的视图
- 决定弹出视图位置的实现思路有两种
// 第一种 : 重写containerViewWillLayoutSubviews方法,用于布局转场动画弹出的控件
override func containerViewWillLayoutSubviews() {
super.containerViewWillLayoutSubviews()
// containerView 非常重要,容器试图
// presentedView() 非常重要,通过该方法能够拿到弹出的视图
presentedView()?.frame = presentViewFrame // 位置尺寸有外界来决定
// 将HUD添加到containerView上
containerView?.insertSubview(HUD, atIndex: 0)
}
// 第二种 : 重写frameOfPresentedViewInContainerView方法,返回容器中view的frame
override func frameOfPresentedViewInContainerView() -> CGRect {
return CGRect(x: 85, y: 50, width: 200, height: 300)
}
- 方法二:
控制器出现的时候会调用该方法
该方法用于返回一个负责转场动画如何出现的对象,需要遵守UIViewControllerAnimatedTransitioning
协议
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// 返回当前控制器,让当前控制器来负责转场怎么出现,并且当前控制器要遵循UIViewControllerAnimatedTransitioning协议
ChaosLog("出现")
// 发送通知,告诉外界状态发生改变
NSNotificationCenter.defaultCenter().postNotificationName(ChaosPresentationManagerDidPresent, object: self)
isPresent = true // 改变标记的值
return self
}
- 方法三:
控制器隐藏的时候会调用该方法
该方法用于返回一个负责转场动画如何消失的对象,需要遵守UIViewControllerAnimatedTransitioning
协议
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
// 返回当前控制器,让当前控制器来负责转场怎么消失,并且当前控制器要遵循UIViewControllerAnimatedTransitioning协议
ChaosLog("消失")
// 发送通知,告诉外界状态发生改变
NSNotificationCenter.defaultCenter().postNotificationName(ChaosPresentationManagerDidPresent, object: self)
isPresent = false // 改变标记的值
return self
}
3.UIViewControllerAnimatedTransitioning协议中的两个重要方法
- 方法一 : 用来告诉系统展示动画和消失动画所用的时长,用来统一转场动画显示和消失所用的时间
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return 0.3
}
重点
方法二 : 专门用于管理modal以什么样的动画展现和消失的,无论是展现还是消失都会调用该方法
<1> 专门用于管理modal以什么样的动画显示
和消失
的,无论展示和消失都会调用这个方法
<2> 只要实现了这个方法,系统就不会默认添加动画了(modal系统默认动画是从上往下钻)
<3> 所有的动画效果都需要我们自己实现,包括需要展示的视图也需要我们自己添加到容器的视图上(containerView)
<4> transitionContext
: 所有动画需要的属性等都保存在上下文中,换而言之就是可以通过transitionContext获取我们想要的东西
func animateTransition(transitionContext: UIViewControllerContextTransitioning)
{
if isPresent { // 显示
willPresentViewController(transitionContext)
} else { // 消失
willDismissViewController(transitionContext)
}
}
// 显示视图的方法
private func willPresentViewController(transitionContext: UIViewControllerContextTransitioning) {
// // 将要modal出来的VC
// let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)
// // 控制toVC显示出来的VC
// let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)
// ChaosLog(toVC)
// ChaosLog(fromVC)
// 对应toVC的View
guard let toView = transitionContext.viewForKey(UITransitionContextToViewKey) else {
return
}
// 对应fromVC的View
// let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)
// 获取containerView
transitionContext.containerView()?.addSubview(toView)
// 动画效果
toView.transform = CGAffineTransformMakeScale(1.0, 0.0)
// layer的锚点默认在中间,动画也是从中间开始,将锚点设置为顶部
toView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.0)
UIView.animateWithDuration(transitionDuration(transitionContext), animations: {
toView.transform = CGAffineTransformIdentity
}) { (_) in
// 注意: 自定义转场动画,在执行完动画之后一定要告诉系统动画执行完毕了
// 刚开始自己忘了,然后PopoverMenu上的TableView不见了
transitionContext.completeTransition(true)
}
}
// dismiss视图的方法
private func willDismissViewController(transitionContext: UIViewControllerContextTransitioning) {
guard let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey) else {
return
}
UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
// menu没有动画消失,而是立即消失的原因是CGFloat不准确,导致动画无法执行.
// 解决方案: 给CGFloat设置一个很小的值即可
fromView.transform = CGAffineTransformMakeScale(1.0, 0.00001)
}, completion: { (_) -> Void in
transitionContext.completeTransition(true)
})
}
自定义转场动画细节问题
1. 导航栏的titlesView中箭头方向改变的问题 : 刚开始的做法是根据选中状态,修改箭头的位置.但是项目中的实际效果为,点击titlesView出现菜单控制器,点击除了titlesView的任何地方菜单控制器消失,如图
- 解决方案 : 在代理方法中有发出通知,外界通过监听通知来改变titlesView中箭头的方向
- 通知的字符串常量
- 分别在菜单控制器显示和消失的方法中发出通知
- 外界通过监听通知来改变titlesView中箭头方向
- 通知的字符串常量
2. 自定义转场动画结束后,一定要告诉系统,动画结束
// 注意: 自定义转场动画,在执行完动画之后一定要告诉系统动画执行完毕了
// 刚开始自己忘了,然后PopoverMenu上的TableView不见了
transitionContext.completeTransition(true)
Swift开发小技巧--自定义转场动画的更多相关文章
- Swift开发小技巧--自定义Log
Swift中的自定义Log OC中有宏的定义,可以定义自己的Log,但是Swif中没有宏的定义,想要实现类似OC中的自定义Log,必须实现以下操作 1.在AppDelegate.swift文件中定义一 ...
- Swift开发小技巧--private访问修饰符报错的情况
1.Swift中的访问修饰符(三个,作用:用来修饰属性,方法和类) public : 最大权限 -- 可以在当前framework和其他framework中访问 internal : 默认的权限 -- ...
- Swift开发小技巧--TabBar中间按钮的添加方案
TabBar中间按钮的添加方案 之前做百思项目的时候,也有一个中间按钮,当时是重写的TabBar,这里介绍一个新的方法 给TabbarVC多添加添加一个控制器,这个控制器的作用仅仅是用来占位的,多了这 ...
- Swift开发小技巧--识别选中照片中的二维码
识别选中照片中的二维码 点击相册按钮,打开用户相册 @IBAction func photoBtnClick(sender: AnyObject) { // 打开相册 // 1.判断是否能够打开相册 ...
- Swift开发小技巧--扫描二维码,二维码的描边与锁定,设置扫描范围,二维码的生成(高清,无码,你懂得!)
二维码的扫描,二维码的锁定与描边,二维码的扫描范围,二维码的生成(高清,无码,你懂得!),识别相册中的二维码 扫描二维码用到的三个重要对象的关系,如图: 1.懒加载各种类 // MARK: - 懒加载 ...
- iOS开发小技巧--自定义带有占位文字的TextView(两种方式)
自定义控件注意或框架注意:自己暴露在外面的属性,一定要重写setter,保证外界与内部的交互性 一.方案一:通过drawRect:方法将文字画到textView中,监听文字改变用的是通知中心(代理也可 ...
- swift项目第八天:自定义转场动画以及设置titleView的状态
如图效果: 一:Home控制器 /* 总结:1:设置登陆状态下的导航栏的左右按钮:1:在viewDidLoad里用三目运算根据从父类继承的islogin的登陆标识来判断用户是否登陆来显示不同的界面.未 ...
- iOS开发自定义转场动画
1.转场动画 iOS7之后开发者可以自定义界面切换的转场动画,就是在模态弹出(present.dismiss),Navigation的(push.pop),TabBar的系统切换效果之外自定义切换动画 ...
- 移动Web开发小技巧
移动Web开发小技巧 添加到主屏后的标题(IOS) name="apple-mobile-web-app-title" content="标题"> 启用 ...
随机推荐
- MMORPG大型游戏设计与开发(part1 of net)
网络模块的设计,是大型多人在线游戏中比较重要的一部分.我之所以将网络模块放到最前面,是因为许许多多的开发者面对这一块的时候充满了疑惑,而且也觉得很神秘和深奥.这些我们面对到的困难,其实是由于我们对这方 ...
- Android常见的按钮监听器实现方式
为按钮(Button)添加响应事件,需要为其设置监听器(Listener).本文总结了Android中常用的几种Button Listener. 第一种:匿名内部类作为事件监听器类 1 2 3 4 5 ...
- VS Code
VS Code VS Code(Visual Studio Code)是由微软研发的一款免费.开源的跨平台文本(代码)编辑器.几乎完美的编辑器. 官网:https://code.visualstudi ...
- 向tiny6410中移植中移植linux-4.5.1内核(最新)
下载linux-4.5.1.tar.gz 解压在任意目录下.我解压在/home/tiny6410/ # tar xvzf linux-4.5.1.tar.gz # cd linux-4.5.1/ 修改 ...
- luogu1097统计数字[noip2007提高组Day1T1]
题目描述 某次科研调查时得到了n个自然数,每个数均不超过1500000000(1.5*10^9).已知不相同的数不超过10000个,现在需要统计这些自然数各自出现的次数,并按照自然数从小到大的顺序输出 ...
- html页面实现自动刷新的几种方法
使用场景: 1. 页面需要定时刷新,实时加载数据(H5中的WebSocket和SSE可以实现局部刷新) 2. 一定时间之后跳转到指定页面(登录注册之类) 3. 前端开发使用伪数据调试html页面(修改 ...
- android 下载文件
import com.example.android.R; import android.app.Activity;import android.os.Bundle;import android.os ...
- jquery noConflict详解
noConflict是防止其他库也用了$作为全局变量而引起的冲突,我们看看jquery是怎么做的 首先jquery在代码的开始部分定义了2个私有变量: _jQuery = window.jQuery ...
- sudo命令使用的几个场景
在linux系统下,普通用户无法直接执行root用户权限下的命令,如果想让普通用户执行只有root用户才能执行的操作命令.下面罗列下经常使用sudo命令的几个场景: 1.用户无权限执行root命令普通 ...
- Android入门篇1-Hello World
一.android studio安装. 二.项目结构 三.运行流程 src->main->AndroidMainifest.xml注册HelloWorldActivity(intent-f ...