SWIFT, 苹果于 2014 年 WWDC(苹果开发者大会) 发布的新开发语言, 可与 Objective-C * 共同运行于 Mac OS 和 iOS 平台, 用于搭建基于苹果平台的应用程序
这篇文章主要为大家详细介绍了纯 swift 实现 ipad 版简单美团界面功能, 具有一定的参考价值, 感兴趣的小伙伴们可以参考一下
一 总体功能图一 : (ipad 竖屏)
二 总体功能图二 : (ipad 横屏)
三 讲解内容
1 搭建美团界面 (掌握)
2 ios8.0 之后的 Popover 的运用 (重点)
3 协议 (掌握)
4 通知 (掌握)
5 细节处理
四总体界面
1 由总体的 app 界面效果, 能看出来, 一个 UIViewController 控制器作为 UINavigationController 的根控制器就能满足条件.
五 导航条设置
1 自定义导航条 : (系统的导航条不能满足需求)
2 创建导航控制器类
3 获取全局的导航条 : (用来作为设置)
- // 获取导航条
- let navigationBar = UINavigationBar.appearanceWhenContainedInInstancesOfClasses([self.classForCoder])
3.1 注意 : 一定要用上面的方法来获取, 不要用下面的方法来获取, 因为通过下面方法获取对导航条的设置, 很有可能会造成导航条呈现黑色的情况.
UINavigationBar.appearance()
4 用图片包装导航条
- // 设置导航条的样式
- navigationBar.setBackgroundImage(UIImage(named: "bg_navigationBar_normal"), forBarMetrics: .Default)
5 注意不要忘了将导航控制器的类型改为自定义类型, 否则会加载不出来的
六 导航条相关内容处理
1 思路 : 通过观察导航条中的按钮, 我们可以看出, 按钮都是由图片; 主标题; 子标题组成的, 所以我们可以通过 xib 来描述, 并且用一个 UIView 将按钮包裹住, 方便修改设置
2 创建继承 UIView 的类, 同时创建同类名的 xib
3 xib 图
4 xib 内部分布结构图
5 如何在 xib 中分离图片和标题之间的距离? 5.1 下图解答
6 通过给 xib 拖线, 拿到内部属性
- // 按钮头像
- @IBOutlet weak var iconButton: UIButton!
- // 头部子标题
- @IBOutlet weak var subtitleLabel: UILabel!
- // 头部标题
- @IBOutlet weak var title_Label: UILabel!
7 给 xib 中的属性提供 set 方法和对应的 get 方法, 方便外边调用修改
- // 对头部标题提供 Set 方法
- var title: String ? {
- didSet {
- return title_Label.text = title
- }
- }
- // 对头部子标题提供 set 方法
- var subtitle: String ? {
- didSet {
- return subtitleLabel.text = subtitle
- }
- }
- // 对按钮头像提供 set 方法 (平常的图片)
- var normalName: String ? {
- didSet {
- return iconButton.setImage(UIImage(named: normalName ! ), forState: .Normal)
- }
- }
- // 对按钮头像提供 set 方法 (点击后的图片)
- var heightName: String ? {
- didSet {
- return iconButton.setImage(UIImage(named: heightName ! ), forState: .Highlighted)
- }
- }
- // 对按钮提供一个 get 方法
- var getIconButton: UIButton {
- get {
- return iconButton
- }
- }
8 提供一个加载 xib 的类方法, 让外界能通过该方法快速创建 xib
- //MARK: - 给类扩展一个方法 (加载 xib)
- extension XFJTopView {
- // 提供一个快速创建 xib 的类方法
- class func topView(title : String, subTitle : String, normalImageName : String, heightImageName : String) ->XFJTopView {
- let topView = NSBundle.mainBundle().loadNibNamed("XFJTopView", owner: nil, options: nil).last! as! XFJTopView
- // 给属性赋值
- topView.title_Label.text = title
- topView.subtitleLabel.text = subTitle
- topView.iconButton.setImage(UIImage(named: normalImageName), forState: .Normal)
- topView.iconButton.setImage(UIImage(named: heightImageName), forState: .Highlighted)
- // 返回通过 xib 创建的对象
- return topView
- }
- }
9 添加顶部的按钮
-> 9.1 思路 : 通过添加到由导航条管理的 item 中的数组中来实现对加载 xib 的时候按钮的添加
-> 9.2 导航控制器的根控制器
-> 9.3 XFJHomeViewController 类对导航条中的 item 的管理 (该部分代码比较多, 我们通过类扩展来实现)
- //MARK: - 设置导航条中的 item
- extension XFJHomeViewController {
- @objc private func setUpTabBarItem() {
- // 设置值 item 的图片 (0)
- let logoItem = UIBarButtonItem(image: UIImage(named: "icon_meituan_logo"), style: .Plain, target: nil, action: nil)
- // 对导航条最左边的 item 赋值
- navigationItem.leftBarButtonItem = logoItem
- // 取消导航条左边的 item 点击
- logoItem.enabled = false
- // 设置其他的 items(一)
- let item1 = XFJTopView.topView("美团", subTitle: "全部分类", normalImageName: "icon_category_-1", heightImageName: "icon_category_highlighted_-1")
- // 设置第一个 item
- let topItem = UIBarButtonItem(customView: item1)
- // 对按钮的监听
- item1.getIconButton.addTarget(self, action: "presentPopTopViewClick", forControlEvents: .TouchUpInside)
- // 赋值
- self.topItem = topItem
- // 设置 items(二)
- let item2 = XFJTopView.topView("广州", subTitle: "全部", normalImageName: "icon_district", heightImageName: "icon_district_highlighted")
- let gzItem = UIBarButtonItem(customView: item2)
- item2.getIconButton.addTarget(self, action: "presentPopGzViewClick", forControlEvents: .TouchUpInside)
- // 赋值
- self.gzItem = gzItem
- // 设置 items(三)
- let item3 = XFJTopView.topView("排序", subTitle: "默认排序", normalImageName: "icon_sort", heightImageName: "icon_sort_highlighted")
- let sortItem = UIBarButtonItem(customView: item3)
- item3.getIconButton.addTarget(self, action: "presentPopSortViewClick", forControlEvents: .TouchUpInside)
- // 赋值
- self.sortItem = sortItem
- // 将 item 添加到数组中
- navigationItem.leftBarButtonItems = [logoItem,topItem,gzItem,sortItem]
- }
- }
七 Popover 的弹出
1 分别创建三个类来管理弹出的 Popover
2 对顶部三个 item 所弹出的控制做懒加载创建, 保证用到的时候在创建
- //MARK: - 懒加载控制器 (一)
- private lazy var categoryVC : XFJCategoryViewController = {
- // 创建控制器
- let categoryVC = XFJCategoryViewController()
- // 设置控制器的样式
- categoryVC.modalPresentationStyle = .Popover
- // 返回控制器
- return categoryVC
- }()
- //MARK: - 懒加载控制器 (二)
- private lazy var districtVC : XFJDistrictViewController = {
- // 创建控制器
- let districtVC = XFJDistrictViewController()
- // 设置控制器的样式
- districtVC.modalPresentationStyle = .Popover
- // 返回控制器
- return districtVC
- }()
- //MARK: - 懒加载控制器 (三)
- private lazy var sortsVC : XFJSortsViewController = {
- // 创建控制器
- let sortsVC = XFJSortsViewController()
- // 设置控制器的样式
- sortsVC.modalPresentationStyle = .Popover
- // 返回控制器
- return sortsVC
- }()
3 根据弹出的 Popover 类型, 我们也可以看出是由两个 UITableView 组成, 并且各占控制器的一半, 那么我们这部分也可以通过 xib 来实现.
-> 3.1 创建一个类来管理, 同时创建 xib
3.2 xib 内部图
4 弹出 Popover(通过在 9.3 中对 item 的监听)
-> 4.1 弹出 Popover 代码块一 :
- //MARK : - 实现监听方法
- extension XFJHomeViewController {@objc private func presentPopTopViewClick() {
- // 弹出位置
- categoryVC.popoverPresentationController ? .barButtonItem = topItem
- // 设置背景颜色
- categoryVC.popoverPresentationController ? .backgroundColor = UIColor.clearColor()
- //model 出控制器
- presentViewController(categoryVC, animated: true, completion: nil)
- // 取消 UIBarButtonItem 的交互
- setDisabled()
- // 设置代理
- categoryVC.popoverPresentationController ? .delegate = self
- }
- }
-> 4.1 弹出 Popover 代码块二:
- extension XFJHomeViewController {@objc private func presentPopGzViewClick() {
- // 弹出位置
- districtVC.popoverPresentationController ? .barButtonItem = gzItem
- // 设置背景颜色
- districtVC.popoverPresentationController ? .backgroundColor = UIColor.clearColor()
- //
- //model 出控制器
- presentViewController(districtVC, animated: true, completion: nil)
- // 取消 UIBarButtonItem 的交互
- setDisabled()
- // 设置代理
- districtVC.popoverPresentationController ? .delegate = self
- }
- }
-> 4.1 弹出 Popover 代码块三 :
- extension XFJHomeViewController {@objc private func presentPopSortViewClick() {
- // 弹出控制器的位置
- sortsVC.popoverPresentationController ? .barButtonItem = sortItem
- // 设置背景颜色
- sortsVC.popoverPresentationController ? .backgroundColor = UIColor.whiteColor()
- //model 出控制器
- presentViewController(sortsVC, animated: true, completion: nil)
- // 取消 UIBarButtonItem 的交互
- setDisabled()
- // 设置代理
- sortsVC.popoverPresentationController ? .delegate = self
- }
- }
八 处理弹出的 Popover 相关数据 (全部由对应的模型来决定)
1 获取 xib 中的对象并且提供一个快速创建 xib 的类方法
- // 左边的 tableView
- @IBOutlet weak var leftTableView: UITableView!
- // 右边的 tableView
- @IBOutlet weak var rightTableView: UITableView!
- // 模型分类数据
- var categories : [XFJCategories]?
- // 地区模块的数据
- var DistrictData : [XFJDistrict]?
- // 定义一个属性, 用来记录用户点击了左侧的哪一行
- var seletIndex : Int?
- // 快速创建 xib 的类方法
- class func lrTableView() ->XFJLRTableView {
- return NSBundle.mainBundle().loadNibNamed("XFJLRTableView", owner: nil, options: nil).last as! XFJLRTableView
- }
- // 分类的子数据
- private var subData : [String]?
2 通过在 xib 中设置代理和数据源实现有关数据源方法
-> 2.1 数据源方法一 : cell 的个数
- //MARK: - 数据源方法
- extension XFJLRTableView: UITableViewDataSource {
- //cell 的个数
- func tableView(tableView: UITableView, numberOfRowsInSection section: Int) - >Int {
- // 判断是左边还是右边
- if tableView == leftTableView { // 左边
- return (delegateSource ? .numberOfRowsInLeft(self)) !
- } else { // 右边
- return subData ? .count ? ?0
- }
- }
-> 2.2 数据源方法二 : cell 的内容
- //cell 的内容
- func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - >UITableViewCell {
- // 创建 cell
- var cell = UITableViewCell ? ()
- // 判断
- if tableView == leftTableView {
- // 创建自定义 cell
- cell = XFJLeftViewCell.leftViewCell(tableView)
- // 设置文字
- cell ? .textLabel ? .text = delegateSource ? .lrTableView(titleDataSource: indexPath.row)
- // 设置头像 (平常图)-- 注意 :lrTableViewWithNormalImageInLeft 千万要注意大小写
- if delegate ? .respondsToSelector("lrTableViewWithNormalImageInLeft:") == true {
- cell ? .imageView ? .image = UIImage(named: (delegateSource ? .lrTableView ! (normalImageInLeft: indexPath.row)) ! )
- }
- // 设置头像 (高亮图)-- 注意 :lrTableViewWithHighlightImageLeft 千万要注意大小写
- if delegate ? .respondsToSelector("lrTableViewWithHighlightImageLeft:") == true {
- cell ? .imageView ? .highlightedImage = UIImage(named: (delegateSource ? .lrTableView ! (highlightImageLeft: indexPath.row)) ! )
- }
- } else {
- cell = XFJRightViewCell.righViewCell(tableView)
- // 设置内容
- cell ? .textLabel ? .text = subData ! [indexPath.row]
- }
- return cell !
- }
-> 2.3 数据源方法三 : 点击 cell 做出的相应数据改变
- //MARK: - 点击左边的 cell
- extension XFJLRTableView: UITableViewDelegate {
- func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
- // 判断是否是左边
- if tableView == leftTableView { // 左边
- // 获取子数据
- subData = delegateSource ? .lrTableView(subDataSource: indexPath.row)
- // 调用协议方法 (传入用户点击的哪行)
- delegate ? .lrTableView(seletLeftButton: indexPath.row)
- // 记录用户点击了左侧的哪行
- seletIndex = indexPath.row
- // 刷新表格
- rightTableView.reloadData()
- } else { // 右边
- // 调用协议方法, 传入右侧点击了哪行和左侧选中了哪行
- delegate ? .lrTableView(seletRightButton: indexPath.row, seletLeftButton: seletIndex ! )
- }
- }
- }
九 创建模型
1 导入 plist 文件
2 创建继承 NSObject 的类, 用来设置需要用到的模型属性
-> 2.1 模型属性一 :(分类中所需要的模型属性)
- var highlighted_icon = String?()
- var icon = String?()
- var name = String?()
- var small_highlighted_icon = String?()
- var small_icon = String?()
- var map_icon = String?()
- var subcategories = [String]?()
-> 2.2 模型属性二 : (全部模块中所需要的模型属性)
- var name = String?()
- var subregions = [String]?()
-> 2.3 模型属性三 : (排序模块中所需要的模型属性)
- var label = String?()
- var value = Int?()
3 在各自管理的类中懒加载模型 (采用 MJ 框架加载模型)
-> 3.1 分类模块中懒加载模型
- // 懒加载模型
- private lazy var categories : [XFJCategories] = {
- let categoriesData = XFJCategories.objectArrayWithFilename("categories.plist") as NSArray
- // 返回模型
- return categoriesData as! [XFJCategories]
- }()
-> 3.2 地区模块中懒加载模型
- // 懒加载
- private lazy var DistrictView :[XFJDistrict] = {
- let DistrictData = XFJDistrict.objectArrayWithFilename("gz.plist") as NSArray
- // 返回模型数据
- return DistrictData as! [XFJDistrict]
- }()
-> 3.3 排序模块中懒加载模型
- // 创建一个属性记录按钮的点击状态
- var previousButton = UIButton()
- // 懒加载
- private lazy var sortsData : [XFJSorts] = {
- // 模型转化
- let sortsDatas = XFJSorts.objectArrayWithFilename("sorts.plist") as NSArray
- // 返回模型
- return sortsDatas as! [XFJSorts]
- }()
十 自定义 cell
1 通过功能图知道 Popover 出来的控制器中 cell 中既展示图片又展示文字, 所以我们通过自定义 cell 来设置 2 自定义左边的 tableViewCell
- class XFJLeftViewCell: UITableViewCell {
- // 左边的 tableView
- class func leftViewCell(tableView: UITableView) - >XFJLeftViewCell {
- // 绑定 cell 类型
- let leftCell = "leftCell"
- var cell = tableView.dequeueReusableCellWithIdentifier(leftCell)
- // 判断 cell 是否为空
- if cell == nil {
- cell = XFJLeftViewCell(style: .Default, reuseIdentifier: leftCell)
- }
- return cell as ! XFJLeftViewCell
- }
- override init(style: UITableViewCellStyle, reuseIdentifier: String ? ) {
- super.init(style: style, reuseIdentifier: reuseIdentifier)
- // 设置背景图片
- backgroundView = UIImageView(image: UIImage(named: "bg_dropdown_leftpart")) selectedBackgroundView = UIImageView(image: UIImage(named: "bg_dropdown_left_selected"))
- }
- required init ? (coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- }
2.1 该方法是在数据源方法中调用的, 用来加载 cell
3 自定义右边的 tableViewCell
- class XFJRightViewCell: UITableViewCell {
- // 右边的 tableView
- class func righViewCell(tableView: UITableView) - >XFJRightViewCell {
- // 定义 cell 的标识
- let rightCell = "rightCell"
- // 创建 cell
- var cell = tableView.dequeueReusableCellWithIdentifier(rightCell)
- // 判断
- if cell == nil {
- cell = XFJRightViewCell(style: .Default, reuseIdentifier: rightCell)
- }
- // 返回 cell
- return cell as ! XFJRightViewCell
- }
- // 设置 cell 的背景图片
- override init(style: UITableViewCellStyle, reuseIdentifier: String ? ) {
- super.init(style: style, reuseIdentifier: reuseIdentifier) backgroundView = UIImageView(image: UIImage(named: "bg_dropdown_rightpart")) selectedBackgroundView = UIImageView(image: UIImage(named: "bg_dropdown_right_selected"))
- }
- required init ? (coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- }
十一 上半部分总结
1 用上面这些方法确实可以达到用户点击 item, 弹出对应的控制器. 但是上面的代码只是写了对其中一个点击 item 弹出的业逻辑, 还有中间的 item 并没与处理, 如果采用这样的方法处理, 那么代码量太多了, 并且看起来也显得没什么技术含量, 我们最终将不会采用这种方法实现.
十二 代理 协议 (最终实现的方案)
1 需要实现的功能 : 通过代理协议的方式, 实现用户点击弹出控制器的左边部分, 显示出右边部分, 并且将对应的头像和主标题, 子标题显示到 item 中
2 定义协议方法 : (包括可实现和可不实现)> 因为 : 当点击左边的 tableView 中的 cell 的时候, 有右边有些内容是空的, 所以如果都定义为必须实现的, 会出现问题
3 定义在 XFJLRTableView 中的协议方法第一部分
- ///MARK : - 定义协议, 用协议的方法来控制 top 中没个按钮的点击, 弹出控制器设置相应的内容
- @objc protocol XFJTableViewDataSource: NSObjectProtocol {
- /// 左边的 cell 显示的总行数 (需要将左边的 tableView 作为参数传递进去)
- func numberOfRowsInLeft(leftTableView: XFJLRTableView) - >Int
- /// 左边的 cell 显示的数据
- func lrTableView(titleDataSource leftRow: Int) - >String ?
- /// 左边的 cell 显示的子数据
- func lrTableView(subDataSource leftRow: Int) - >[String]
- /// 左边的 cell 显示的平常图片 (有些是不存在图片的)
- optional func lrTableView(normalImageInLeft leftRow: Int) - >String
- /// 左边的 cell 显示的高亮图片 (有些是不存在图片的)
- optional func lrTableView(highlightImageLeft leftRow: Int) - >String
- }
4 设置代理 :(分类模块代理)
- /// 设置代理 (处理弹出的控制器)
- weak var delegateSource : XFJTableViewDataSource?
5 注意 : 在对协议实现的部分方法中, 已经在 XFJLRTableView 类中的数据源方法这种实现了或者是做出了判断.(上面数据源方法中有介绍)
6 对分类用户点击后实现协议相关的方法
-> 6.1 设置对应的控制器为代理
- override func viewDidLoad() {
- super.viewDidLoad()
- // 快速创建 xib
- let lrTableView = XFJLRTableView.lrTableView()
- // 设置尺寸
- lrTableView.frame = view.bounds
- // 添加 tableView
- view.addSubview(lrTableView)
- // 设置代理 (处理的是弹出控制器的部分)
- lrTableView.delegateSource = self
- // 设置代理 (处理的是用户点击 cell 的业务逻辑)
- lrTableView.delegate = self
- }
7 实现协议方法
- ///MARK : - 实现分类的代理方法 (处理的是弹出控制器的部分)
- extension XFJCategoryViewController: XFJTableViewDataSource {
- ///MARK : - 左侧 cell 的行数
- func numberOfRowsInLeft(leftTableView: XFJLRTableView) - >Int {
- return categories.count
- }
- ///MARK : - 左侧 cell 的标题
- func lrTableView(titleDataSource leftRow: Int) - >String ? {
- // 取出模型数据
- let categorie = categories[leftRow]
- return categorie.name
- }
- ///MARK : - 左侧 cell 的子标题
- func lrTableView(subDataSource leftRow: Int) - >[String] {
- // 取出模型数据
- let categorie = categories[leftRow]
- // 判断
- return categorie.subcategories ? ?[]
- }
- ///MARK : - cell 平常图片
- func lrTableView(normalImageInLeft leftRow: Int) - >String {
- // 取出模型数据
- let categorie = categories[leftRow]
- return categorie.small_icon !
- }
- ///MARK : - cell 的高亮图片
- func lrTableView(highlightImageLeft leftRow: Int) - >String {
- // 取出模型数据
- let categorie = categories[leftRow]
- return categorie.small_highlighted_icon !
- }
- }
8 处理用户点击 item 中的某行 cell, 将 cell 中显示的图片和主标题, 子标题显示在 item 中
-> 8.1 定义协议 :
- ///MARK : - 定义协议, 用来传递当用户选择了弹出的控制器中的某行, 将 cell 中显示的内容显示到对应的 top 按钮中
- @objc protocol XFJTableViewDelegate: NSObjectProtocol {
- // 点击了左边, 告诉代理选择了左边的哪一行, 只要告诉代理不需返回参数
- func lrTableView(seletLeftButton leftRow: Int)
- // 点击了右边, 高度代理点击了右边的哪一行, 同时告诉代理选中了左边的哪一行, 不需要返回
- func lrTableView(seletRightButton rightRow: Int, seletLeftButton leftRow: Int)
- }
-> 8.2 设置代理 :
- /// 设置代理 (处理选中弹出的控制器中的哪一行)
- weak var delegate : XFJTableViewDelegate?
-> 8.3 实现协议中的方法
- ///MARK : - 实现分类的代理方法 (处理的是用户点击 cell 的业务逻辑)
- extension XFJCategoryViewController: XFJTableViewDelegate {
- // 用户点击了左侧, 告诉代理点击了左侧的哪一行
- func lrTableView(seletLeftButton leftRow: Int) {
- // 从模型中取出数据
- let catrgoryData = categories[leftRow]
- // 判断左侧是否有子数据
- let subCatroyData = catrgoryData.subcategories ? .count
- // 如果没有子数据, 就将数据发送给外界, 进行数据更改
- if subCatroyData == 0 {
- // 通过通知的方式发送
- NSNotificationCenter.defaultCenter().postNotificationName(XFJCategoryNotification, object: nil, userInfo: [XFJCategoryNotificationKey: catrgoryData])
- }
- }
- // 用户点击了右侧, 高度代理点击了右侧哪一行, 同时告诉代理选中了左侧哪一行
- func lrTableView(seletRightButton rightRow: Int, seletLeftButton leftRow: Int) {
- // 从模型中获取数据
- let catrgoriesData = categories[leftRow]
- // 取出子数据
- let subCatrgoriesData = catrgoriesData.subcategories ! [rightRow]
- // 发送通知
- NSNotificationCenter.defaultCenter().postNotificationName(XFJCategoryNotification, object: nil, userInfo: [XFJCategoryNotificationKey: catrgoriesData, XFJSubCategoryNotificationKey: subCatrgoriesData])
- }
- }
十三 通知
1 我们是如何将 cell 中对应的文字和图片显示到 item 中?
-> 1.1 我们采用发送通知的方法将相关数据传递到 item 中
2 创建一个文件用来保存通知需要的参数
- // 分类
- let XFJCategoryNotification = "XFJCategoryNotification"
- let XFJCategoryNotificationKey = "XFJCategoryNotificationKey"
- let XFJSubCategoryNotificationKey = "XFJSubCategoryNotificationKey"
- // 地区
- let XFJDistrictNotification = "XFJDistrictNotification"
- let XFJDistrictNotificationKey = "XFJDistrictNotificationKey"
- let XFJSubDistrictNotificationKey = "XFJSubDistrictNotificationKey"
- // 排序
- let XFJSortsNotification = "XFJSortsNotification"
- let XFJSortsNotificationKey = "XFJSortsNotificationKey"
3 发送通知 (分类模块)-> 通知书写位置: 协议方法中
-> 3.1 代码块一 :
- // 用户点击了左侧, 告诉代理点击了左侧的哪一行
- func lrTableView(seletLeftButton leftRow: Int) {
- // 从模型中取出数据
- let catrgoryData = categories[leftRow]
- // 判断左侧是否有子数据
- let subCatroyData = catrgoryData.subcategories ? .count
- // 如果没有子数据, 就将数据发送给外界, 进行数据更改
- if subCatroyData == 0 {
- // 通过通知的方式发送
- NSNotificationCenter.defaultCenter().postNotificationName(XFJCategoryNotification, object: nil, userInfo: [XFJCategoryNotificationKey: catrgoryData])
- }
- }
-> 3.2 代码块二 :
- // 用户点击了右侧, 高度代理点击了右侧哪一行, 同时告诉代理选中了左侧哪一行
- func lrTableView(seletRightButton rightRow: Int, seletLeftButton leftRow: Int) {
- // 从模型中获取数据
- let catrgoriesData = categories[leftRow]
- // 取出子数据
- let subCatrgoriesData = catrgoriesData.subcategories ! [rightRow]
- // 发送通知
- NSNotificationCenter.defaultCenter().postNotificationName(XFJCategoryNotification, object: nil, userInfo: [XFJCategoryNotificationKey: catrgoriesData, XFJSubCategoryNotificationKey: subCatrgoriesData])
- }
4 接收通知 : 虽然发送的通知是匿名通知, 但是最好让能将数据提供给谁的一方接收通知, 这样也方便设置相关数据
-> 4.1 item 是属于 XFJHomeViewController 类的, 就让该类来接收通知, 并实现通知中的方法
-> 4.2 接收通知代码 :
- // 接收分类通知
- NSNotificationCenter.defaultCenter().addObserver(self, selector: "categoriesNotic:", name: XFJCategoryNotification, object: nil)
- // 接收地区通知
- NSNotificationCenter.defaultCenter().addObserver(self, selector: "districtNotic:", name: XFJDistrictNotification, object: nil)
- // 接收排序通知
- NSNotificationCenter.defaultCenter().addObserver(self, selector: "sortsNotic:", name: XFJSortsNotification, object: nil)
-> 4.3 移除通知 (重要点)
- // 移除通知
- deinit {
- NSNotificationCenter.defaultCenter().removeObserver(self)
- }
5 实现接收通知中的方法
-> 5.2 分类
- ///MARK : - 实现接收分类通知的中调用的方法
- extension XFJHomeViewController {
- @objc private func categoriesNotic(nic : NSNotification) {
- // 取出通知中的内容
- let catrgoryData = nic.userInfo![XFJCategoryNotificationKey] as! XFJCategories
- // 此处 (有可能没有子数据, 所以这里不需强转)
- let subCatroyData = nic.userInfo![XFJSubCategoryNotificationKey]
- // 设置数据 (获取顶部的 view)
- let categoryTopView = topItem?.customView as! XFJTopView
- // 子数据
- let count = catrgoryData.subcategories?.count
- // 判断
- if count == 0 {
- categoryTopView.title = "美团"
- categoryTopView.subtitle = catrgoryData.name
- }else{
- categoryTopView.title = catrgoryData.name
- categoryTopView.subtitle = subCatroyData as! String?
- }
- // 设置图标
- categoryTopView.normalName = catrgoryData.icon
- categoryTopView.heightName = catrgoryData.highlighted_icon
- // 退出 poper
- categoryVC.dismissViewControllerAnimated(true) { () -> Void in
- //dismiss 后允许交互
- self.setEnabled()
- }
- }
- }
-> 5.2 地区
- ///MARK : - 实现接收地区通知的中调用的方法
- extension XFJHomeViewController {
- @objc private func districtNotic(disNic : NSNotification){
- // 取出通知中的内容
- let districtData = disNic.userInfo![XFJDistrictNotificationKey] as! XFJDistrict
- // 此处 (有可能没有子数据, 所以这里不需强转)
- let subDistrictData = disNic.userInfo![XFJSubDistrictNotificationKey]
- // 设置数据 (获取顶部的 view)
- let districtTopView = gzItem?.customView as! XFJTopView
- // 子数据
- let count = districtData.subregions?.count
- // 判断
- if count == 0 {
- districtTopView.title = "美团"
- districtTopView.subtitle = districtData.name
- }else{
- districtTopView.title = districtData.name
- districtTopView.subtitle = subDistrictData as! String?
- }
- // 退出 poper
- districtVC.dismissViewControllerAnimated(true) { () -> Void in
- //dismiss 后允许交互
- self.setEnabled()
- }
- }
- }
-> 5.3 排序
- ///MARK : - 实现接收排序通知的中调用的方法
- extension XFJHomeViewController {@objc private func sortsNotic(sortsNic: NSNotification) {
- // 获取通知中的内容
- let sortsData = sortsNic.userInfo ! [XFJSortsNotificationKey] as ! XFJSorts
- // 获取顶部的 view
- let sortsView = sortItem ? .customView as ! XFJTopView
- // 设置数据
- sortsView.subtitle = sortsData.label
- // 移除 poper
- sortsVC.dismissViewControllerAnimated(true) { () - >Void in
- //dismiss 后允许交互
- self.setEnabled()
- }
- }
- }
十四 细节处理
1 我们发现当运行在横屏的时候, 没有问题, 但是当在运行的之后转换为竖屏, 导航条中 item 间的距离会被拉伸, 这怎么解决呢?
-> 1.1 产生这种现象的原因 : autoresizing 导致屏幕旋转的时候, 子控件跟随父控件的拉伸而拉伸
-> 1.2 解决 :(如下图)> 将正方形中间的红线去除就可以
2 当点击某个 item 的时候, 发现再点击其他的 item 的时候, 前一个 item 并没有退出, 这样给用户的体验不好. 我们通过代码来设置.
-> 2.1 在监听用户点击的按钮中让所有的 item 都取消交互调用下面代码
- @objc private func setDisabled() {
- topItem?.enabled = false
- gzItem?.enabled = false
- sortItem?.enabled = false
- }
-> 2.2 在实现接收通知中调用的方法中, 在 poper 被 dismiss 的时候, 允许用户交互, 调用下面代码来允许交互
- @objc private func setEnabled() {
- topItem?.enabled = true
- gzItem?.enabled = true
- sortItem?.enabled = true
- }
-> 2.3 在实现对 item 按钮的监听方法中, 我们设置 poper 的代理为当前控制器 (这里只说明一段代码, 其它模块也是一样的)
- // 设置代理
- categoryVC.popoverPresentationController ? .delegate = self
-> 2.4 实现代理方法
- ///MARK: - 实现 popver 代理方法
- extension XFJHomeViewController: UIPopoverPresentationControllerDelegate {
- func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
- // 允许交互
- setEnabled()
- }
- }
十五 总结
1 这篇博客我写的可能有点乱, 代码太多, 我也没办法具体到某一点, 只是说了大概, 介绍了协议可以实现这种情况的方法, 同时对通知的运用也是捎带了, 没有怎么细说. 希望你们尽量看吧, 看不懂的话, 在给我私信吧. 能帮到大家的, 我一定帮忙.
2 最后还是那句话, 大家如果觉得我写的博客还写的话, 麻烦大家多多关注我的官方博客, 谢谢!
来源: http://www.phperz.com/article/18/0217/361467.html