第二天--框架的搭建和未登陆界面的实现

作者: 改变自己_now | 来源:发表于2016-08-20 21:49 被阅读246次

    前言

    第一天我们把项目如何托管到github中,今天主要记录基本框架的搭建,和简单的UI实现。碰到的问题如下

    1、swift中如何动态加载控制
    2、swift中本地文件的序列化和容错处理
    3、swift按钮事件的监听写法
    4、swift中cocopods使用SnapKit
    5、如何自定义View和xib定义view以及swift中类方法的写法
    6、swift中协议的写法
    7、swift中如何用闭包来代替协议

    最后简单的实现效果如下图

    QQ20160820-0@2x.png

    1、动态加载控制

    首先继承一个UITabBarController的子类

    class YJBaseTabBarViewController: UITabBarController
    

    在该控制中添加我们需要添加的子控制器,子控制需要包装一层导航控制器。一般我不直接使用系统的控制器,所以还写了下面两个类

    class YJBaseNaviViewController: UINavigationController
    class YJBaseTableViewController: UITableViewController
    

    我们的控制器都继承于 YJBaseTableViewController

    在YJBaseTabBarViewController中viewDidLoad中添加子控制,定义一个方法,用来添加子控制器

       // MARK: 添加子控器
       private func  addChildViewController(childController: UIViewController ,title:String, imageName:String) {
        
        let main = childController
        
        main.title = title;
        main.tabBarItem.image = UIImage(named: imageName)
        main.tabBarItem.selectedImage = UIImage(named: imageName + "_highlighted")
        
        //创建一个nav
        let navi = YJBaseNaviViewController()
        navi.addChildViewController(main)
        addChildViewController(navi)
    
    }
    

    我们还可以根据服务器返回的类名来动态加载我们的子控制器,于是我又定义了下面的方法

    // MARK: 通过字符串动态加载控制
    
    private func addChildViewController(childControllerName: String,title:String, imageName:String) {
        
        
        //在swift中有动态命名空间的概念,默认未工程名字
        let prodouctName = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
        
        //获取类名
        let className:AnyClass? = NSClassFromString(prodouctName + "." + childControllerName)
        
        // 将类名转化为指定的类型
        let vcCls = className as! UIViewController.Type
        
        // 调用初始化方法
        let childVC = vcCls.init()
        
        
        addChildViewController(childVC, title: title, imageName: imageName)
    
        
    }
    

    这里主要碰到的问题swift中如何通过字符串来获取类名,然后再通过类来创建需要的控制器。上面的代码我想已经写的够详细了。

    2、本地文件的序列化处理,使用do和catch来处理序列化容错

    由于我们没有网络返回的数据,我们就直接模拟动态加载,在本地添加一个json文件,然后我们解析json文件,然后加载我们的控制器
    方法如下:

    // 解析本地json
        let jsonPath = NSBundle.mainBundle().pathForResource("localSettings.json", ofType: nil)
        
        if let resultPath = jsonPath {
            
            print(resultPath)
            
             //转为data
            let fileData = NSData.init(contentsOfFile: resultPath)
            
            if let realData = fileData  {
                
                //在这里序列化,序列化可能会出现,抛异常
                
                do {
                
                    // 这里正常解析
                    let jsonArr = try NSJSONSerialization.JSONObjectWithData(realData, options: .MutableContainers)
                    
                    //遍历数组,这里需要注意因为json返回的是Anyobject对象,需要将其转为数组
                    for dict in jsonArr as![[String:String]] {
                    
                        addChildViewController(dict["vcName"]!, title: dict["title"]!, imageName: dict["imageName"]!)
                    }
                    
                    print("解析成功")
                 
                    
                }
                catch {
                
                    print(error)
                    // 异常处理,如果解析json失败,就自己创建
                    //创建首页
                    addChildViewController("YJMainViewController", title: "首页", imageName:"tabbar_home")
                    
                    //消息
                    addChildViewController("YJMessageViewController", title: "消息", imageName:"tabbar_message_center")
                    
                    //发现
                    addChildViewController("YJAttentionViewController", title: "发现", imageName:"tabbar_discover")
                    
                    //我的
                    addChildViewController("YJMineViewController", title: "我的", imageName:"tabbar_profile")
                }
                
                
            }
            
        }
    

    3、按钮点击事件的写法。

    上图中间的按钮是我们自己添加一个的按钮,添加点击写法真心蛋筒,需要注意的是响应事件方法也不能用private来修饰
    以前添加点击事件的可以这样写:

      btn.addTarget(self, action: "composeClick", forControlEvents: .TouchUpInside)
    

    现在上面的写法已经弃用改用下面的写法,但是蛋痛是写的时候根本没有提示。

      btn.addTarget(self, action: #selector(YJBaseTabBarViewController.composeClick), forControlEvents: .TouchUpInside)
    

    4、cocopods的使用

    上面我们基本就能搭建好整体的框架,接下就需要实现未登陆界面,这里有UI布局,我们如果用代码的话,为了适配我们需要用autolayout来布局,我使用第三方库SnapKit,为了方便管理使用Cocopods来安装
    a、首先需要安装cocopods,如果没有安装的话。

    安装命令:sudo gem install cocoa pod
    

    有可能会碰到安装出错,如下

    0DA1D724-CEC7-4851-9D96-4C0FC10CDB4A.png

    则用下面的安装命令

    sudo gem install -n /usr/local/bin cocoa pods
    

    b、cd 到你工程目录

    pod init
    

    然后用Xcode打开编辑

    open -a Xcode Podfile
    

    写入下面内容

     use_frameworks!
    platform :ios, '9.0'
    pod 'SnapKit'
    

    关闭在终端中执行

     pod install
    

    等待安装完成


    5754B61B-3058-4ED3-897B-C50B25A3F84D.png

    就可以通过上图那个打开我们的工程,这样我们就能使用第三方SnapKit

    5、6、7、自定义view和xib自定义view类方法、协议、闭包

    首页的未登陆界面,用来代码来自定义view,用Snapkit来布局UI。
    代码自定义view必须写下面的方法

    // 主页的访客视图、

        override init(frame: CGRect) {
        
        super.init(frame: frame)
        
        addSubview(rorationView)
        
        addSubview(hourseView)
        
        addSubview(introduceLabel)
        
        addSubview(attentionButton)
        
    }
    
    // 如果是自定义xib view必须实现这个方法,不是的就不需要实现
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    

    下面是使用SnapKit布局的部分代码如下

      // 在这里写布局相关的代码
        weak var weakSelf = self
    
        //旋转视图
        rorationView.snp_makeConstraints { (make) in
            
            make.size.equalTo(CGSizeMake(200, 200))
            make.center.equalTo(weakSelf!)
        }
    

    其中有个关注按钮的点击事件需要传递给控制器,OC最容易想到的使用代理。swift中代理协议的写法必须继承:NSObjectProtocol协议,首先是声明协议。

      //申明协议
      protocol YJMainVisitorViewDelegate:NSObjectProtocol {
    
    // 关注按钮点击
        func attentioButtonClick()
    }
    

    在该view申明一个代理,主要需要使用weak关键字来修饰

     // 申明代理
       weak var delegate:YJMainVisitorViewDelegate?
    

    在按钮响应事件中实现

    //MARK: 按钮点击事件

        func attentionClick()  {
        
        // 感觉这个写法要比OC简单
         delegate?.attentioButtonClick()
        }
    

    这样想要监听关注点击事件只要成为它代理,遵守协议就能监听点击事件了。使用如下
    首先,遵守协议

    class YJMainViewController: YJBaseTableViewController,YJMainVisitorViewDelegate
    

    然后成为visitorView的代理

       let visitorView = YJMainVisitorView()
            
            visitorView.delegate = self
    

    最后实现代理方法

    //MARK:YJMainVisitorViewDelegate
    func attentioButtonClick() {
        
        print("我点击关注按钮了")
    }
    

    上面的代理协议实现过程,走了六个步骤,实在让人蛋痛,于是想到了闭包和OC 的block有点类似,于是就尝试了下。
    写法如下
    首先在view中申明一个闭包属性

     // 定义一个闭包
    var attentClickBlock:(()->())?
    

    然后在响应事件中

     //MARK: 按钮点击事件
    func attentionClick()  {
       
        // 
        attentClickBlock?()
    }
    

    最后在控制器中的使用如下

        let visitorView = YJMainVisitorView()
           
            visitorView.attentClickBlock = {
            
                print("我闭过包来的")
            }
    

    我还是习惯用闭包,因为简单啊,我是个怕麻烦的人。

    消息的未登陆页面,我们采用xib关联的方式来实现,必须重写下面的方法

      // 自定义xib重写这个方法
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
         
    }
    

    其他实现和OC基本一样我就不描述了,另外就是swift中类方法的写法,使用 internal和 class两个关键字来声明

       //MARK: 获取messageVisitorView,声明类方法 internal
    internal class func  messageVisitorView() ->(YJMessageVisitorView){
    
        return NSBundle.mainBundle().loadNibNamed("YJMessageVisitorView", owner: nil, options: nil).first as! YJMessageVisitorView
    }
    

    今天的内容到此结束,如果有什么错误的地方,希望指正,毕竟swift我用的不多,不是很熟,谢谢!!!

    相关文章

      网友评论

        本文标题:第二天--框架的搭建和未登陆界面的实现

        本文链接:https://www.haomeiwen.com/subject/ucpisttx.html