如图效果:

一:Home控制器

/*
总结:1:设置登陆状态下的导航栏的左右按钮:1:在viewDidLoad里用三目运算根据从父类继承的islogin的登陆标识来判断用户是否登陆来显示不同的界面。未登录则显示访客界面,若是登陆则构建登陆界面 2:登陆界面需要:设置左右导航栏的按钮:在viewDidLoad里封装设置登陆界面导航栏按钮的方法,将具体代码封装在HomeViewController的extension中,定义方法属性或是懒加载要考虑用private或是fileprivate来修饰,在当前class类中调用当前类的方法可以省略掉self,给UIBarButtonItem写一个分类,新建swiftFile,导入import UIKit框架,然后写扩展:extension UIBarButtonItem {},在写分类的时候既可以提供class类方法也可以提供构造方法,但是一般为了外界调用方便都会提供构造函数方法,并且是便利构造函数。3:外界调用: navigationItem.leftBarButtonItem = UIBarButtonItem("navigationbar_friendattention", target: self, action: #selector(HomeViewController.clickLeftItem))其中 #selector(HomeViewController.clickLeftItem),这么写也可以在监听的方法中传入参数,同样监听按钮点击的方法也封装在当前类的extension中,在监听按钮点击的方法中若是定义为private或是fileprivate则用@objc 来修饰。4:一个按钮可以设置不同状态下的图片,可通过根据设置按钮的不同状态来显示不同的按钮图片:1:一个按钮设置不同的显示状态:
titleViewBtn.isSelected = !titleViewBtn.isSelected 2:多个按钮的切换,可以设置currentBtn,设置按钮的三部曲 **/
import UIKit class HomeViewController: RHBaseTableViewController { //MARK:-0:闭包懒加载属性 //1:懒加载titleView
fileprivate lazy var titleViewButton :RHTitleViewButton = { let titleViewBtn = RHTitleViewButton()
//1:设置标题
titleViewBtn.setTitle("HELLO_SWIFT", for: .normal)
//2:设置点击的监听方法
titleViewBtn.addTarget(self, action: #selector(HomeViewController.clickTitleView), for: .touchUpInside)
return titleViewBtn
}() //2:懒加载Animator:通过闭包来设置titleView的状态
/* 1: 1:注意:在闭包中如果使用当前对象的属性或者调用方法,也需要加self
两个地方需要使用self : 1> 如果在一个函数中出现歧义 2> 在闭包中使用当前对象的属性和方法也需要加self 2:在新建类定义闭包的时候,必须写上新建类的类型,否则会报错:
fileprivate lazy var Animator :RHAnimator
2: 闭包的循环引用:1:RHAnimator对闭包有一个强引用,其又为home的属性,所以home又对RHAnimator有一个强引用,在闭包中有引用了home的对象的属性,所以对当前控制器对象home也会有一个强引用,相互之间引用从而造成循环引用 2:解决办法:在参数列表前加[weak self]进行修饰,解决循环引用,[weak self]得到的类型为可选类型,若是可选类型能保证一定有值也就是不为nil,则可以进行强制解包,若是不能确定1:则可以用guard进行校验 2:可以在等号左边用?,则表示有值则执行代码,若是为nil,则不执行后面的代码:self?.titleViewButton.isSelected = presented
*/
fileprivate lazy var Animator :RHAnimator = RHAnimator {[weak self] (presented) in self?.titleViewButton.isSelected = presented
}
override func viewDidLoad() {
super.viewDidLoad() //根据标识字段,构建访客或是登陆视图
isLogin ? setupNavagationBar() : visitorView.rotationImage() } } //MARK:-3:设置首页的导航栏
extension HomeViewController { //1:设置首页的导航栏
fileprivate func setupNavagationBar() { //1:设置首页左侧的导航栏按钮.
navigationItem.leftBarButtonItem = UIBarButtonItem("navigationbar_friendattention", target: self, action: #selector(HomeViewController.clickLeftItem)) //2:设置首页的右侧的导航栏按钮
navigationItem.rightBarButtonItem = UIBarButtonItem("navigationbar_pop", target: self, action: #selector(HomeViewController.clickRightItem)) //3:设置titleView
navigationItem.titleView = titleViewButton//此处添加titleView的代码会多次调用layoutsubView } } //MARK:-4:监听按钮的点击 extension HomeViewController { //1:点击的是左侧ietm
@objc fileprivate func clickLeftItem(leftItem:UIBarButtonItem) { DLog(message: "点击的是左侧的按钮------\(leftItem)")
} //2:点击的是右侧的item
@objc fileprivate func clickRightItem(rightItem:UIBarButtonItem) { DLog(message: "点击的是右侧的按钮")
} //3:点击的是titleView的btn
@objc fileprivate func clickTitleView (titleViewBtn:RHTitleViewButton){ /*
自定义转场动画:1:将弹出的view封装为一个控制器,一般将业务逻辑复杂的view都封装为一个控制器:创建弹出的控制器let popController = RHPopMenuViewController() 2:设置控制器的弹出样式:自定义样式 popController.modalPresentationStyle = .custom,枚举值就用.custom
3:设置转场代理: popController.transitioningDelegate = Animator,1:将转场代理设为Animator,也就是将内部代理的方法封装在Animator的内部,2:需要给Animator传递一个frame,3:弹出控制器: present(popController, animated: true, completion: nil),当调用当前类内部的属性或是方法的时候,可以省略调用self,但是在闭包内需要加上self
注意:必须得是先去遵守协议,才能设置代理,否则系统会报错
*/ //1:创建弹出的控制器
let popController = RHPopMenuViewController() //2:设置控制器的弹出样式:自定义样式
popController.modalPresentationStyle = .custom //3:设置转场代理
popController.transitioningDelegate = Animator //4:设置弹出的frame
Animator.presentFrame = CGRect(x: , y: , width: , height: ) //5:弹出控制器
present(popController, animated: true, completion: nil) } }

二:RHPopMenuViewController:xib自定义:首先创建控制器RHPopMenuViewController定义xib,拖入UIImageView,设置背景图片,会产生拉伸效果,在图2处可以处理其拉伸效果:设置竖直方向拉伸

三:封装转场动画的代理方法

import UIKit
/*
总结:此类用于封装转场动画的代理方法
1:定义类的属性:1:需要外界访问的时候就不需要加关键字private,或是fileprivate,定义属性的时候必须有初始化值或是定义成可选类型,定义的Bool标识默认取值为false,定义成可选类型,确定取值就强制解包,不确定的时候可以用guard进行校验,或是在等号左侧不进行校验也不进行强制解包,用?,表示可选类型若为nil,则不执行后面的代码,若不为nil则执行 2:定义闭包来进行回调,闭包的类型:(参数列表)->(返回值列表),以属性定义闭包,要么给闭包初始化赋值,要么定义为可选类型,要么会报错:var callBack : ((_ presented:Bool)->())?,若是想成为内部参数,也就是外部调用的时候不显示,则可以用_+空格来表示。 2:重写init方法:1:注意:如果自定义了一个构造函数,但是没有对默认构造函数init()进行重写,那么自定义的构造函数会覆盖默认的init()构造函数,也就是在外部不能调用构造函数的方法。2:重写init构造函数:防止自定义函数覆盖掉默认的init()构造函数,
override init() {
super.init()
} required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} 注意:当我们重写init或是重写init(frame)构造函数的时候,必须重写required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} 3:自定义构造函数:将闭包作为参数传进自定义的构造函数中,@escaping:声明为逃逸闭包,
init(callBack : @escaping ((_ presented:Bool)->())) { self.callBack = callBack
}
说白了:逃逸闭包和非逃逸闭包本质的区别就是:闭包作为参数传进函数体中的时候,如果立即调用闭包,就为非逃逸闭包,如果不是立即调用闭包,将这个闭包保存在一个函数外部定义的变量中,在外部调用,逃逸出函数体,则为逃逸闭包, */
class RHAnimator: NSObject { //MARK:-1:设置转场代理的属性 //1:设置是否弹出的属性标识
fileprivate var present = false //2:提供frame属性供外界去设置
var presentFrame = CGRect.zero //3:定义闭包来回调,控制导航栏标题的显示状态(定义为可选类型)
var callBack : ((_ presented:Bool)->())? /*
注意:如果自定义了一个构造函数,但是没有对默认构造函数init()进行重写,那么自定义的构造函数会覆盖默认的init()构造函数 */ //4:重写init构造函数:防止自定义函数覆盖掉默认的init()构造函数
override init() {
super.init()
} required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
} //5:自定义构造函数
/*
当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸。当你定义接受闭包作为参数的函数时,你可以在参数名之前标注 @escaping,用来指明这个闭包是允许“逃逸”出这个函数的。 一种能使闭包“逃逸”出函数的方法是,将这个闭包保存在一个函数外部定义的变量中。举个例子,很多启动异步操作的函数接受一个闭包参数作为 completion handler。这类函数会在异步操作开始之后立刻返回,但是闭包直到异步操作结束后才会被调用。在这种情况下,闭包需要“逃逸”出函数,因为闭包需要在函数返回之后被调用。例如: var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
} 若是可选类型在左侧可以直接给可选类型赋值,但是在之后使用可选类型的时候一定要进行解包
*/ init(callBack : @escaping ((_ presented:Bool)->())) { self.callBack = callBack
} } //MARK:-2:转场动画的代理
extension RHAnimator:UIViewControllerTransitioningDelegate { //1:设置弹出控制器的
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { /*
1:返回值为UIPresentationController,所以自定义继承系统的RHPresentationController,创建对象传递frame并返回
2:UIPresentationController为弹出的控制器,可以对其进行设置 */
let presentVC = RHPresentationController(presentedViewController: presented, presenting: presenting)
presentVC.presentedFrame = presentFrame
return presentVC
} /*
1:在系统API中,代理方法有option的可以选择实现,没有标注option的则为在代理方法中必须实现的方法
2:实现弹出动画和消失动画的方法:1:设置弹出的标识 ,为了利用闭包回调标识,以便在home控制器中回调设置titleView的状态 2:在利用闭包的时候,因为其为可选类型,所以在使用的时候一定要进行解包,可选类型在左侧的时候,可以给可选类型直接赋值 3:返回值为UIViewControllerAnimatedTransitioning, return self为设置UIViewControllerAnimatedTransitioning的代理 3:实现UIViewControllerAnimatedTransitioning代理方法: */ //2:设置的是弹出的动画
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { //回调弹出标识来控制titleView的显示状态
present = true
self.callBack!(present) return self } //3:设置的是消失的动画
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
//回调弹出标识来控制titleView的显示状态
present = false
self.callBack!(present)
return self
} } extension RHAnimator:UIViewControllerAnimatedTransitioning { /** 1:遵守UIViewControllerAnimatedTransitioning代理,实现代理方法来设置动画的方法:1:设置动画弹出的时间 2:通过转场上下文transitionContext获取转场弹出或是消失的view,根据是否弹出的标识来动画控制view的弹出和消失:定义两个方法,根据标识来控制消失还是弹起的动画。 2: 获取`转场的上下文`:可以通过转场上下文获取弹出的View和消失的View
UITransitionContextFromViewKey : 获取消失的View
UITransitionContextToViewKey : 获取弹出的View 1.获取弹出的View: 1:let presentView = transitionContext.view(forKey: UITransitionContextViewKey.to)! 获取的presentView是一个可选类型,能保证其一定有值,所以可以进行强制解包 2:添加到containerView上transitionContext.containerView.addSubview(presentView) 执行动画:设置transform的缩放效果,x方向不需要缩放,y方向缩放值为0,锚点anchorPoint,在其中心点的位置,所以要想设置其从上往下拉的效果就设置锚点y的值为0,不要使用传递函数体的参数的时候可以使用(_)来表示,在完成动画之后要设置必须告诉转场上下文你已经完成动画, transitionContext.completeTransition(true) presentView.transform = CGAffineTransform(scaleX: 1.0, y: 0.0)
presentView.layer.anchorPoint = CGPoint(x: 0.5, y: 0)
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { presentView.transform = CGAffineTransform.identity }) { (_) in // 必须告诉转场上下文你已经完成动画
transitionContext.completeTransition(true)
} } */
//1:设置动画弹出的时间
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 0.5
} //2:通过转场上下文获取转场弹出或是消失的view,根据是否弹出的标识来动画控制view的弹出和消失
func animateTransition(using transitionContext: UIViewControllerContextTransitioning){ present ? animateForpresent(transitionContext) : animateFordissmiss(transitionContext)
} /*
获取`转场的上下文`:可以通过转场上下文获取弹出的View和消失的View
UITransitionContextFromViewKey : 获取消失的View
UITransitionContextToViewKey : 获取弹出的View */ //3:动画弹出view
fileprivate func animateForpresent (_ transitionContext:UIViewControllerContextTransitioning) { // 1.获取弹出的View
let presentView = transitionContext.view(forKey: UITransitionContextViewKey.to)! // 2.将弹出的View添加到containerView中
transitionContext.containerView.addSubview(presentView) //3:执行动画
presentView.transform = CGAffineTransform(scaleX: 1.0, y: 0.0)
presentView.layer.anchorPoint = CGPoint(x: 0.5, y: )
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { presentView.transform = CGAffineTransform.identity }) { (_) in // 必须告诉转场上下文你已经完成动画
transitionContext.completeTransition(true)
} } //4:动画消失view
fileprivate func animateFordissmiss (_ transitionContext:UIViewControllerContextTransitioning){ // 1.获取消失的View
let dissmissView = transitionContext.view(forKey: UITransitionContextViewKey.from) //3:执行动画
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: { dissmissView?.transform = CGAffineTransform.identity }) { (_) in
dissmissView?.removeFromSuperview()
// 必须告诉转场上下文你已经完成动画
transitionContext.completeTransition(true)
} } }

四: 封装弹出的控制器

/*
总结:1:此类是用于设置弹出view的frame和添加蒙版 2:重写UIPresentationController的containerViewWillLayoutSubviews方法,override来重写,在此方法内不要忘记调用super 2:重写此方法:1:设置弹出view的frame:presentedView?.frame = presentedFrame,因为presentedView为弹出view,为可选类型,确定有值可以强制拆包,或是直接?使用,不为nil则执行,为nil则不执行,但是在之后的代码中使用需要进行解包,可以给可选类型进行直接赋值。但是不能将可选类型直接赋值给其他的变量 2:添加蒙版:1:在containerView上添加蒙版,containerView?.insertSubview(cover, at: 0),2:设置颜色: cover.backgroundColor = UIColor(white: 0.8, alpha: 0.9),white为1满色的时候为白色,0为黑色,alpha透明度,为0完全透明 3:设置frame: cover.frame = (containerView?.bounds)!也可以:containerView!.bounds 3:添加手势:let tap = UITapGestureRecognizer(target: self, action: #selector(RHPresentationController.clickBg))
cover.addGestureRecognizer(tap),手势监听的方法也写在extension中,显示移除弹出的view,然后是dissmiss掉控制器
*/
import UIKit class RHPresentationController: UIPresentationController { //MARK:-1:设置属性 //1:弹出view的尺寸
var presentedFrame = CGRect.zero //2:懒加载遮盖的view
fileprivate lazy var cover = UIView() //3:重写布局函数设置弹出view的frame:不要忘记调用super
override func containerViewWillLayoutSubviews() { super.containerViewWillLayoutSubviews()
//1:设置弹出view的frame
presentedView?.frame = presentedFrame //2:添加蒙版
setUpCover() }
} extension RHPresentationController { //1:添加蒙版
fileprivate func setUpCover() { //1:添加到containnerView中
containerView?.insertSubview(cover, at: )
cover.backgroundColor = UIColor(white: 0.8, alpha: 0.2)
cover.frame = (containerView?.bounds)!//containerView!.bounds //2:添加手势
let tap = UITapGestureRecognizer(target: self, action: #selector(RHPresentationController.clickBg)) cover.addGestureRecognizer(tap)
} } extension RHPresentationController { @objc fileprivate func clickBg() { //1:移除遮盖
cover.removeFromSuperview() //2:dissmiss掉控制器
presentedViewController.dismiss(animated: true, completion: nil)
}
}

swift项目第八天:自定义转场动画以及设置titleView的状态的更多相关文章

  1. Swift开发小技巧--自定义转场动画

    自定义转场动画 个人理解为重写了被弹出控制器的modal样式,根据自己的样式来显示modal出来的控制器 例:presentViewController(aVC, animated: true, co ...

  2. iOS 自定义转场动画

    代码地址如下:http://www.demodashi.com/demo/12955.html 一.总效果 本文记录分享下自定义转场动画的实现方法,具体到动画效果:新浪微博图集浏览转场效果.手势过渡动 ...

  3. iOS自定义转场动画实战讲解

    iOS自定义转场动画实战讲解   转场动画这事,说简单也简单,可以通过presentViewController:animated:completion:和dismissViewControllerA ...

  4. 第六十五篇、OC_iOS7 自定义转场动画push pop

    自定义转场动画,在iOS7及以上的版本才开始出现的,在一些应用中,我们常常需要定制自定义的的跳转动画 1.遵守协议:<UIViewControllerAnimatedTransitioning& ...

  5. iOS自定义转场动画的实现

    iOS中熟悉的是导航栏中的push和pop这两种动画效果,在这里我们可以自己实现自己想要的一些转场动画 下面是我自己创建转场动画的过程 1.新建一个文件继承自NSObject ,遵循协议UIViewC ...

  6. Storyboard 自定义转场动画

    在storyboard中,segue有几种不同的类型,在iphone和ipad的开发中,segue的类型是不同的.在iphone中,segue 有:push,modal,和custom三种不同的类型, ...

  7. 一行代码实现自定义转场动画--iOS自定义转场动画集

    WXSTransition 这款非常不错,力推 这是作者源码简书地址: http://www.jianshu.com/p/fd3154946919 这是作者源码github地址 https://git ...

  8. iOS 自定义转场动画浅谈

    代码地址如下:http://www.demodashi.com/demo/11612.html 路漫漫其修远兮,吾将上下而求索 前记 想研究自定义转场动画很久了,时间就像海绵,挤一挤还是有的,花了差不 ...

  9. iOS开发自定义转场动画

    1.转场动画 iOS7之后开发者可以自定义界面切换的转场动画,就是在模态弹出(present.dismiss),Navigation的(push.pop),TabBar的系统切换效果之外自定义切换动画 ...

随机推荐

  1. CentOS下编译安装Apache

    与Apache 2.2.x相比,Apache 2.4.x提供了很多性能方面的提升,包括支持更大流量.更好地支持云计算.利用更少的内存处理更多的并发等.除此之外,还包括性能提升.内存利用.异步 I/O的 ...

  2. java(运算符,控制流程语句,函数 )

    运算符 数据类型转换: 小数据类型-------->大数据类型(自动类型转换) 大数据类型--------->小数据类型(强制类型转换) 强制类型转换的格式: 小数据类型  变量名 = ( ...

  3. MarkDown study:

    #MarkDown study:## 区块元素:### 段落和换行 段落:由一个或多个连续的文本行组成,它的前后要有一个以上的空行(空行的定义是显示上看起来像是空的,便会被视为空行.比方说,若某一行只 ...

  4. tree ---树状显示

    tree命令以树状图列出目录的内容. 语法 tree(选项)(参数) 选项 -a:显示所有文件和目录: -A:使用ASNI绘图字符显示树状图而非以ASCII字符组合: -C:在文件和目录清单加上色彩, ...

  5. android:giavity和layout_gravity的差别

    android:gravity: 是对该view中内容的限定.比方一个button 上面的text. 你能够设置该text 相对于view的靠左,靠右等位置. android:layout_gravi ...

  6. win8用久了变得非常慢, 磁盘占用100%

    完美解决方式:  直接重装win7 完美解决这个问题 在网上查了非常久也没找到有效方法, 求教

  7. code blocks主题颜色配置

    添加配置文件 注意:在添加这些自定义配置文件之前一定要先将之前的文件配置备份! 在添加时一定要确保Code::Blocks**没有**在运行!下载下面的文件,并将其添加到C:\Users\<你的 ...

  8. Flume的Collector

    Collector的作用是将多个Agent的数据汇总后,加载到Storage中.它的source和sink与agent类似. 数据源(source),如: collectorSource[(port) ...

  9. mahout算法库(四)

    mahout算法库 分为三大块 1.聚类算法 2.协同过滤算法(一般用于推荐) 协同过滤算法也可以称为推荐算法!!! 3.分类算法 算法类 算法名 中文名 分类算法               Log ...

  10. 洛谷 P3817 小A的糖果

    P3817 小A的糖果 题目描述 小A有N个糖果盒,第i个盒中有a[i]颗糖果. 小A每次可以从其中一盒糖果中吃掉一颗,他想知道,要让任意两个相邻的盒子中加起来都只有x颗或以下的糖果,至少得吃掉几颗糖 ...