ipad版简单美团界面功能实现(纯swift编写)

一 总体功能图一 : (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 最后还是那句话,大家如果觉得我写的博客还写的话,麻烦大家多多关注我的官方博客,谢谢!!!!

时间: 2024-10-13 01:14:26

ipad版简单美团界面功能实现(纯swift编写)的相关文章

ipad版Qzone(纯swift编写)

一 app大致框架图 : (竖屏) 二 app大致框架图 : (横屏) 三 知识点 1 自动布局(熟悉) 2 协议(熟悉) 3 横屏和竖屏的配置(掌握) 4 细节处理 四 布局登录界面和处理业逻辑 1 自动布局效果图 2 账号和密码相关设置 --> 2.1 账号 --> 2.2 密码 3 创建一个登录控制器,用来处理登录模块相关业务逻辑 4 该部分需要的相关属性(通过从storyboard中拖线得到) class XFJLoginViewController: XFJBaseViewContr

iOS界面布局之三——纯代码的autoLayout及布局动画

iOS界面布局之三--纯代码的autoLayout及布局动画 一.引言 关于界面布局,apple的策略已经趋于成熟,autolayout的优势在开发中也已经展现的淋漓尽致.除了使用storyBoard进行布局约束的拖拽,有时我们也需要在代码中进行autolayout的布局设置,Masonry库可以方便的创建约束属性,实际上,我们也没有必要再使用系统原生的代码来创建和设置约束,这篇博客只作为使用的方法备忘.前几篇布局介绍的链接如下: 使用autoresizing进行界面布局:http://my.o

iPad版微信终于来临了 微信5.4版搜索更智能 转账就是发消息

等待甚久的iPad版微信终于来临了!昨日微信iOS版本更新至5.4.0.16,新增功能包括搜索公众号.识别图中二维码.面对面收钱,同时适配iPad. 1.先来揭开iPad版微信应用的面纱 微信已有iPhone和Mac版应用,但并没有独立的iPad版应用.此次更新后,微信推出了适配iPad的版本.用户除了输入手机号码登录iPad微信外,还可通过扫描二维码的方式来登录. iPad登录方式与网页版有相同之处,用户打开iPad版应用后,需用手机扫描iPad上出现的二维码,点击“登录iPad微信”确认,但

加壳神器——WinLicense界面功能汉化

WinLicense提供了最强和具伸缩性的技术,使开发者可以安全地分发他们软件的试用版和完全版.下面介绍WinLicense界面功能(汉化) 一.应用程序信息(Application Information) software选项后面点击后会出现一个管理模块,选择"ADD"添加一个需要加密的程序,然后填好信息点"update",然后选中刚编辑好的一项(也可以是从前编辑好需要保护的)双击就OK了. 二.保护选项(Protection Options) 一共17个选项,

.net请求Webservice简单实现天气预报功能

很久没有接触Webservice的知识,今天稍微复习了一下关于webservice,简单做了一个天气预报的功能,虽然界面丑的厉害,但功能算是实现了,以下是效果展示. 这东西没什么难点,只是天气预报的功能在网站类的开发中会经常用到,所以就简单写下,以便以后查阅. 1.新建一个网站或者web应用程序,添加一个aspx页面,用于展示天气数据.(这个应该不用细讲吧) 2.在网上找一个免费的天气预报的接口,我用的是Webxml网站的,地址如下: http://webservice.webxml.com.c

Servlet实现简单的登陆功能(带验证码)

"纸上得来终觉浅",动手比看书印象更深,学到的更多.下面用Servlet实现简单的登陆功能,来巩固对Servlet的学习. 1.在WEB-INF下新建一个名为index.html作为登陆界面. index.html代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title>

简单实现下载功能--jsp,servlet

刚到公司,前天给我的第一个小任务,虽然只是做个简单的下载功能. 但一开始还是花了不少时间去理解导师的意思,而且还要用到一些公司的库类,花了一个下午才做好. 大概有三种方法 1.直接用a标签跳转到指定位置的目标文件.  <a href="doc/help.txt" /></a>(文件是位于doc文件夹下help.txt)(不推荐这种方法,而且这跳转会直接打开文件) 2.jsp跳转然后直接在jsp里面写下载功能 <a href="download.j

DuiVision开发教程(2)-如何写一个简单的界面程序

基于DuiVision界面库开发的界面程序主要包括如下几部分内容: 1.资源定义,包括图片资源.各个窗口界面的xml定义文件 2.事件处理类代码,用于处理界面响应消息 3.其他业务逻辑代码 下面举例说明如何写一个简单的界面程序. 第一步:使用VC向导创建一个有两个tab页面的DuiVision工程 向导生成的解决方案文件如下: 默认有两个工程,分别是DuiVision库和应用程序工程.自动生成的代码目录中bin目录下的内容那个如下,bkimg目录存放窗口背景图片,skins目录存放图片资源,xm

atitit.D&amp;D drag&amp;drop拖拽文件到界面功能 html5 web 跟个java swing c#.net c++ 的总结

atitit.D&D drag&drop拖拽文件到界面功能 html5 web 跟个java swing c#.net c++ 的总结 1. DND的操作流程 1 2. Html5 注解事件 document.dragover >>preventDefault 1 3. 代码(js) 1 4. C++ 实现拖曳 2 5. QT拖拽功能简介 - pcsuite的专栏 - 博客频道 - CSDN.NET.htm 2 1. DND的操作流程 Dragenter 事件::更改提示的颜色