仓库github/DrawController(github.com/sascha/Draw…)
是一个Swift语言编写的抽屉库。它可以传入一个中心视图控制器,一个左侧视图控制器,并由一个MaxDrawerWidth属性。创建完毕后,中心视图控制器的视图内容占据全部屏幕;当执行打开抽屉的函数时,整个中心控制的视图内容一起向右平移MaxDrawerWidth这么宽,并且显示左侧视图控制器的内容到屏幕上,内容占满屏幕,但是宽度不超过MaxDrawerWidth指定的值。

研究此代码库的时候,发现它是一个很好的解说Container View Controller[developer.apple.com/library/con…] 概念的例子。这里面:

  1. 类DrawerController就是一个Container View Controller
  2. 其他的视图控制器就是Child View Controller
  3. 第一个类和其他类构成了父子关系
  4. 视图控制器内的视图其实都是放置到DrawerController.view之内的

我把此库内的关于动画和手势的代码全部去掉,专门留下特定于这些控制器交互的代码留下。从1000多行的代码抽取出来247行的代码如下:

 import UIKitvar drawerController : DrawerPage?@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate {var window : UIWindow?func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {window = UIWindow()drawerController = DrawerPage()window!.rootViewController = drawerControllerwindow!.rootViewController!.view.backgroundColor = .bluewindow!.makeKeyAndVisible()return true}}class DrawerPage : DrawerBase{init(){super.init(CenterPage(),LeftPage())}// 哄编译器开心的代码required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)}}class DrawerBase : DrawerController{init(_ center : UIViewController,_ left : UIViewController){super.init(centerViewController: center, leftDrawerViewController: left)}// 从入门到入门:// 1. What exactly is init coder aDecoder?// 2. What does the question mark means in public init?(coder aDecoder: NSCoder)?required init?(coder aDecoder: NSCoder) {fatalError("init(coder:) has not been implemented")}}class LeftPage: UIViewController {var count = 0var label : UILabel!override func viewDidLoad() {super.viewDidLoad()self.view.backgroundColor = .whitelabel   = UILabel()label.frame = CGRect(x: 100, y: 100, width: 120, height: 50)label.text =  "Left"view.addSubview(label)let button   = UIButton(type: .system)button.frame = CGRect(x: 120, y: 150, width: 120, height: 50)button.setTitle("Close",for: .normal)button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)view.addSubview(button)}@objc func buttonAction(_ sender:UIButton!){drawerController?.toggleLeftDrawerSide(animated: true, completion: nil)}}class CenterPage: UIViewController {var label : UILabel!override func viewDidLoad() {super.viewDidLoad()self.view.backgroundColor = .whitelabel   = UILabel()label.frame = CGRect(x: 100, y: 100, width: 120, height: 50)label.text =  "Center"view.addSubview(label)let button   = UIButton(type: .system)button.frame = CGRect(x: 120, y: 150, width: 120, height: 50)button.backgroundColor = .bluebutton.setTitle("Left Page Drawer",for: .normal)button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)view.addSubview(button)}@objc func buttonAction(_ sender:UIButton!){drawerController?.toggleLeftDrawerSide(animated: true, completion: nil)}@objc func buttonAction1(_ sender:UIButton!){
//        drawerController?.toggleRightDrawerSide(animated: true, completion: nil)}}// code impleopen class DrawerController: UIViewController {fileprivate var _centerViewController: UIViewController?fileprivate var _leftDrawerViewController: UIViewController?fileprivate var _leftDrawerWidth = DrawerDefaultWidthopen var centerViewController: UIViewController? {get {return self._centerViewController}}open var leftDrawerViewController: UIViewController? {get {return self._leftDrawerViewController}}open var leftDrawerWidth: CGFloat {get {return self._leftDrawerWidth}}open var shadowRadius = DrawerDefaultShadowRadiusopen var shadowOpacity = DrawerDefaultShadowOpacityfileprivate lazy var childControllerContainerView: UIView = {let a = UIView(frame: self.view.bounds)self.view.addSubview(a)return a}()fileprivate lazy var centerContainerView: DrawerCenterContainerView = {let centerFrame = self.childControllerContainerView.boundslet centerContainerView = DrawerCenterContainerView(frame: centerFrame)centerContainerView.autoresizingMask = [.flexibleWidth, .flexibleHeight]centerContainerView.backgroundColor = UIColor.clearself.childControllerContainerView.addSubview(centerContainerView)return centerContainerView}()open fileprivate(set) var openSide: DrawerSide = .center {didSet {if self.openSide == .center {self.leftDrawerViewController?.view.isHidden = true}self.setNeedsStatusBarAppearanceUpdate()}}public required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)}override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)}public init(centerViewController: UIViewController, leftDrawerViewController: UIViewController?) {super.init(nibName: nil, bundle: nil)self.setCenter(centerViewController)self.setDrawer(leftDrawerViewController,for:.left)}fileprivate func childViewController(for drawerSide: DrawerSide) -> UIViewController? {var childViewController: UIViewController?switch drawerSide {case .left:childViewController = self.leftDrawerViewControllercase .center:childViewController = self.centerViewController}return childViewController}fileprivate func sideDrawerViewController(for drawerSide: DrawerSide) -> UIViewController? {var sideDrawerViewController: UIViewController?if drawerSide != .center {sideDrawerViewController = self.childViewController(for: drawerSide)}return sideDrawerViewController}fileprivate func updateShadowForCenterView() {self.centerContainerView.layer.masksToBounds = falseself.centerContainerView.layer.shadowRadius = shadowRadiusself.centerContainerView.layer.shadowOpacity = shadowOpacityif let shadowPath = centerContainerView.layer.shadowPath {let currentPath = shadowPath.boundingBoxOfPathif currentPath.equalTo(centerContainerView.bounds) == false {centerContainerView.layer.shadowPath = UIBezierPath(rect: centerContainerView.bounds).cgPath}} else {self.centerContainerView.layer.shadowPath = UIBezierPath(rect: self.centerContainerView.bounds).cgPath}}open func toggleLeftDrawerSide(animated: Bool, completion: ((Bool) -> Void)?) {self.toggleDrawerSide(.left, animated: animated, completion: completion)}open func toggleDrawerSide(_ drawerSide: DrawerSide, animated: Bool, completion: ((Bool) -> Void)?) {assert({ () -> Bool inreturn drawerSide != .center}(), "drawerSide cannot be .None")if self.openSide == DrawerSide.center {self.openDrawerSide(drawerSide,completion: completion)} else {if (drawerSide == DrawerSide.left && self.openSide == DrawerSide.left) {self.closeDrawer(animated: animated, completion: completion)} else if completion != nil {completion!(false)}}}fileprivate func openDrawerSide(_ drawerSide: DrawerSide,completion: ((Bool) -> Void)?) {assert({ () -> Bool inreturn drawerSide != .center}(), "drawerSide cannot be .None")if let vc = self.leftDrawerViewController{vc.view.isHidden = falsevar newFrame: CGRectnewFrame = view.framenewFrame.size.width = _leftDrawerWidthvc.view.frame = newFrame//            vc.view.frame = vc.evo_visibleDrawerFrame}func panRight(_ view : UIView,_ value : CGFloat){var newFrame: CGRectnewFrame = view.framenewFrame.origin.x = valueview.frame = newFrame}panRight(centerContainerView, _leftDrawerWidth)self.openSide = drawerSide}fileprivate func setDrawer(_ vc: UIViewController?, for drawerSide: DrawerSide) {assert({ () -> Bool inreturn drawerSide != .center}(), "drawerSide cannot be .None")let currentSideViewController = self.sideDrawerViewController(for: drawerSide)if currentSideViewController == vc {return}self._leftDrawerViewController = vcif vc != nil {self.addChildViewController(vc!)vc!.didMove(toParentViewController: self)self.childControllerContainerView.addSubview(vc!.view)self.childControllerContainerView.sendSubview(toBack: vc!.view)vc!.view.isHidden = true}}fileprivate func setCenter(_ vc: UIViewController?) {self._centerViewController = vcif vc != nil {self.addChildViewController(vc!)vc!.didMove(toParentViewController: self)self.centerContainerView.addSubview(vc!.view)self._centerViewController!.view.frame = self.centerContainerView.boundsself.updateShadowForCenterView()}}open func closeDrawer(animated: Bool, completion: ((Bool) -> Void)?) {let newFrame = self.childControllerContainerView.boundsself.setNeedsStatusBarAppearanceUpdate()self.centerContainerView.frame = newFrameself.openSide = .center}open override func viewDidLoad() {super.viewDidLoad()self.view.backgroundColor = UIColor.black}static let DrawerDefaultWidth: CGFloat = 210.0 //280.0static let DrawerDefaultShadowRadius: CGFloat = 10.0static let DrawerDefaultShadowOpacity: Float = 0.8typealias  DrawerCenterContainerView =  UIViewpublic enum DrawerSide: Int {case centercase left}}复制代码

这里的代码,很关键的是在DrawerController内的view中,创建了一个子视图叫做childControllerContainerView,其内在创建一个子视图centerContainerView,它们几个的大小都是屏幕大小,视图层次为:

--view
----childControllerContainerView
------centerContainerView复制代码

并约定好:

  1. 全部的Center View Controller的视图全部放置到centerContainerView内
  2. 全部的left View Controller和right View Controller的视图全部放置到centerContainerView内
  3. left View Controller和right View Controller的视图放置完毕后,需要首先隐藏起来,并且sendToBack,保证它是不可见的,也不会遮挡任何Center View Controller的内容

这样当指定打开抽屉函数时,centerContainerView整体平移,如果打开左边的抽屉,就向右移动,反之亦然。从而Center View Controller的视图也就跟着平移。并同时把抽屉视图(left View Controller和right View Controller的视图)显示出来,但是宽度不超过MaxDrawerWidth。

通过以上分析,可以加强对Container View Controller概念的理解。

Swift iOS : 代码分析DrawController相关推荐

  1. 第三方微信授权登录的iOS代码分析

    微信已经深入到每一个App的缝隙,最常用的莫过分享和登录了,接下来就以代码的形式来展开微信登录的相关说明,至于原理级别的Oauth2.0认证体系请参考微信开放平台的相关说明和图示 . 微信登录授权开发 ...

  2. SonarQube iOS 代码扫描插件(Objective-C/Swift/Infer/sonar-swift)

    仓库地址:https://github.com/tal-tech/sonar-swift 欢迎 Star. 介绍 静态代码扫描是一种检测项目代码的方式,能够在不运行代码的情况下对代码进行扫描,可以扫描 ...

  3. iOS使用OCLint做静态代码分析

    iOS使用OCLint做静态代码分析 为什么要做代码检查? 检查代码是否误写或者错写,导致一些问题的产生,不能及时发现 减少工程的警告,防止后续系统版本更新的不兼容问题 规范代码风格,变量和方法的命名 ...

  4. iOS(一):Swift纯代码模式iOS开发入门教程

    Swift纯代码模式iOS开发入门教程 项目初始化(修改为纯代码项目) 安装第三方库(以`SnapKit`库为例) 桥接OC库(QMUIKit) 封装视图并进行导航跳转 示例:使用 `TangramK ...

  5. 如何提高go代码覆盖率_如何通过静态分析提高iOS代码质量

    随着项目的扩大,依靠人工codereview来保证项目的质量,越来越不现实,这时就有必要借助于一种自动化的代码审查工具:程序静态分析. 程序静态分析(Program Static Analysis)是 ...

  6. 插件代码_我们开源了一款 SonarQube iOS 代码扫描插件

    背景: 我们在公司(好未来)内部开发了一套基于 SonarQube 的静态代码扫描服务,得益于 SonarQube 开源版本本身的功能,我们可以直接复用支持主流的编程语言,但 SonarQube 的开 ...

  7. swift/dart代码规范检查工具介绍

    swift/dart代码规范检查工具介绍 简介: 本篇主要介绍swift和dart代码规范检查工具,以及他们的工作原理,操作过程,代码规范规则. 1 swift代码检查工具-swiftlint 1.1 ...

  8. ios APP加密探究几维安全iOS 代码混淆效果参考

    几维安全ios代码混淆效果参考: 什么是加密 加密是在二进制的程序中植入一段代码,在运行的时候优先取得程序的控制权,做一些额外的工作.大多数病毒就是基于此原理. 加密作用 加壳的程序可以有效阻止对程序 ...

  9. C语言 03-第一个C程序代码分析

    本文目录 一.代码分析 二.开发和运行C程序的步骤 三.总结 说明:这个C语言专题,是学习iOS开发的前奏.也为了让有面向对象语言开发经验的程序员,能够快速上手C语言.如果你还没有编程经验,或者对C语 ...

最新文章

  1. javascript中重要概念-闭包-深入理解
  2. php 正则 回溯,PHP正则匹配绕过
  3. 【机器视觉】 HDevelop语言基础(四)-流程控制语句
  4. 操作方法:Maven的Spring Boot和Thymeleaf
  5. 前台等待事件 oracle,Oracle等待事件之buffer busy waits
  6. jQuery中文手册, jQuery API, jQuery UI, 分页插件 下载
  7. 进入阿里做测试员遥不可及?这里或许有你想要的答案
  8. 查看Sql语句执行速度
  9. 一键安装Tengine服务器,TengineRPM(LTMP)构建高效、稳定、安全、易用的Web平台
  10. VB代码VB小程序:实现USB摄像头视频图像的监控、截图、录像
  11. 高级项目管理师/高项考试十大管理论文模板
  12. 【计算机毕业设计】疫情社区管理系统的设计与实现
  13. 学计算机应用的必懂知识,学习计算机应用基础心得体会
  14. 不伤虫蚁,使虫蚁远离的方法
  15. 分享一款免费OPC UA服务器
  16. 华为od统一考试B卷【最少面试官数】C++ 实现
  17. 【移动安全实战篇】————3、Android应用程序破解入门
  18. C#中接口(Interface)与抽象类(abstract)的区别
  19. 20150113-下雨天在窗前
  20. 【参考文献】视网膜色素上皮细胞生长培养

热门文章

  1. Redis监控利器---Redis State
  2. 智能一代云平台(二十九):通用mapper的改造
  3. SCPPO(二十五):从导数据看如何将一天过出多天的效果
  4. 美国人民:机器人好棒棒,花钱买一个?1000块不能再高了
  5. Waymo无人车卷入严重事故!车身损毁严重,安全员受轻伤
  6. 李开复创业9年再看世界:中美科技成平行宇宙,VC也要+AI
  7. 刚刚,自动驾驶路测国家规范出台:无人车即将开上更多实际道路
  8. 传微软移动设备部门开始扩招员工
  9. Dom-Attribute对象
  10. openstack network