美文网首页
02-项目搭建

02-项目搭建

作者: 月下独酌灬 | 来源:发表于2016-05-19 22:56 被阅读52次

项目搭建

课程目标

  1. 熟悉 Swift 语法
  2. 搭建系统主体框架结构
  3. 对比与 OC 开发的异同
  4. 纯代码搭建框架

创建文件

准备工作

删除模板文件

  • ViewController.swift
  • Main.storyboard
  • LaunchScreen.xib

创建项目结构

主目录 Classes

二级目录

目录名 说明
Model 数据模型
View 视图和控制器
ViewModel 业务逻辑模型
Tools 工具类

View 子目录

目录名 说明
Main 主要
Home 首页
Message 消息
Compose 撰写
Discover 发现
Profile

View中每个文件夹 子目录

目录名 说明
Controller 控制器
View 自定义View控件

创建项目文件

Main

目录 Controller
Main HMMainViewController.swift(:UITabBarController)

功能模块

目录 Controller
Home HMHomeTableViewController.swift
Message HMMessageTableViewController.swift
Discover HMDiscoverTableViewController.swift
Profile HMProfileTableViewController.swift

细节

  • 每个 ViewController 继承自 UITableViewController
  • 修改 AppDelegate 中的 didFinishLaunchingWithOptions 函数,设置启动控制器
window?.rootViewController = MainViewController()

添加子控制器

功能需求

  • 由于采用了多视图控制器的设计方式,因此需要通过代码的方式向主控制器中添加子控制器

文件准备

  • 将素材文件夹中的 TabBar 拖拽到 Assets.xcassets 目录下

代码实现

添加第一个视图控制器

override func viewDidLoad() {
    super.viewDidLoad()

    addChildViewController()
}

private func addChildViewController() {
    tabBar.tintColor = UIColor.orangeColor()

    let vc = HomeTableViewController()
    vc.title = "首页"
    vc.tabBarItem.image = UIImage(named: "tabbar_home")

    let nav = UINavigationController(rootViewController: vc)

    addChildViewController(nav)
}

重构代码抽取参数

/// 添加控制器
///
/// - parameter vc       : 视图控制器
/// - parameter title    : 标题
/// - parameter imageName: 图像名称
private func addChildViewController(vc: UIViewController, title: String, imageName: String) {
    //设置标题
    vc.title = title
    //设置图片
    vc.tabBarItem.image = UIImage(named: imageName)
    vc.tabBarItem.selectedImage = UIImage(named: "\(imageName)_selected")
    //使用导航控制器包裹起来
    let nav = UINavigationController(rootViewController: vc)
    addChildViewController(nav)
}
  • 扩充调用函数,添加其他控制器
/// 添加所有子控制器
private func addChildViewControllers() {
    addChildViewController(HMHomeTableViewController(), title: "首页", imageName: "tabbar_home")
    addChildViewController(HMMessageTableViewController(), title: "消息", imageName: "tabbar_message_center")
    addChildViewController(HMDiscoverTableViewController(), title: "发现", imageName: "tabbar_discover")
    addChildViewController(HMProfileTableViewController(), title: "我", imageName: "tabbar_profile")
}

UITabBar调整

遇到问题:

  • tabBar上的图片与文字显示的颜色不对,应该怎么去调整?

调整方式:

  • 第1种.一起设置
//设置UITabBar的TintColor属性
UITabBar.appearance().tintColor = UIColor.orangeColor()

这种方式可以把TabBar上显示的图片与文字的颜色一并设置

  • 第2种.分开设置
    • 设置图片:
      • 设置图片按原来的颜色渲染:
        设置tabBarItem的selectedImage属性的时候
//UIImageRenderingMode --> 渲染模式
//设置默认的图片
vc.hildController.tabBarItem.image = UIImage(named: imageName)?.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
//设置选中的图片
vc.tabBarItem.selectedImage = UIImage(named: "\(imageName)_selected")?.imageWithRenderingMode( UIImageRenderingMode.AlwaysOriginal)
  • 也可以在Assets.xcassets目录下,找到对应图片,利用右边控制面板设置其渲染的模式:
  • 设置文字:可以利用tabBarItem的setTitleTextAttributes方法给title添加属性
//文字颜色的属性
let textColorAttr = [
    NSForegroundColorAttributeName: UIColor.orangeColor()
]
//设置选中文字颜色
vc.tabBarItem.setTitleTextAttributes(textColorAttr, forState: UIControlState.Selected)
  • 可以利用这种方法调整UItabBar上的文字大小:
//设置字体的属性
let textFontAttr = [
    NSFontAttributeName: UIFont.systemFontOfSize(12)
]
vc.tabBarItem.setTitleTextAttributes(textFontAttr, forState: UIControlState.Normal)

注意:后面state是Normal

第2种方式更加灵活,可以应对UITabBar上图片颜色不一样的设计

其他

如果以后在公司里面开发,美工给的切图是把文字与图标切在一张图片上的,如:

allproducts.png allproducts_s.png

这个时候我们只设置tabBarItem的image(或者selectedImage)的话,图片会显示 在上半部分的位置:

allproducts_effects.png

解决方法:

//设置偏移量,解决把图片放在tabBar中间的问题
childController.tabBarItem.imageInsets = UIEdgeInsetsMake(5, 0, -5, 0)
allproducts_effects_right.png

自定义 TabBar

功能需求

  • 在 4 个控制器切换按钮中间增加一个撰写按钮
  • 点击撰写按钮能够弹出发表微博的控制器

需求分析

  • 自定义 TabBar
  • 计算控制器按钮位置,在中间添加一个 撰写 按钮

思路

  • 加号按钮的大小与其他 tabBarItem 的大小是一致的
  • 添加加号按钮到TabBar中
  • 遍历查找到其他4个UITabBarButton,设置宽度并调整位置
  • 将撰写按钮放在自定义的UITabBar中间位置
  • 在UITabBar内部监听撰写按钮的点击事件,通过闭包回调到控制器

代码实现

  • 按钮的初始化
/// 撰写按钮
lazy var composeButton: UIButton = {
    let button = UIButton()

    //给按钮添加点击事件(因为button最重要的就是点击事件,所以写在前面)
    button.addTarget(self, action: "composeButtonClick", forControlEvents: UIControlEvents.TouchUpInside)

    //设置按钮不同状态的图片与背景图片
    button.setImage(UIImage(named: "tabbar_compose_icon_add"), forState: UIControlState.Normal)
    button.setImage(UIImage(named: "tabbar_compose_icon_add_highlighted"), forState: UIControlState.Highlighted)
    button.setBackgroundImage(UIImage(named: "tabbar_compose_button"), forState: UIControlState.Normal)
    button.setBackgroundImage(UIImage(named: "tabbar_compose_button_highlighted"), forState: UIControlState.Highlighted)

    //设置大小
    button.sizeToFit()

    return button
}()
  • 设置按钮位置
/// 调整子控件的位置在layoutSubviews里面调整
override func layoutSubviews() {
    super.layoutSubviews()

    //设置加号按钮位置
    //调整子控件的center,不能依靠于父控制的center,因为你知道父控件是放在什么地方的
    composeButton.center = CGPoint(x: frame.width * 0.5, y: frame.height * 0.5)

    ///每一个按钮的宽度
    let childW = frame.size.width / 5
    //定义脚标记录当前button的位置
    var index = 0

    //遍历子控件调整'UITabBarButton'的宽度与位置
    for childView in subviews {

        //如果当前遍历的View是UITabBarButton
        if childView.isKindOfClass(NSClassFromString("UITabBarButton")!) {

            //设置按钮的宽
            childView.frame.size.width = childW
            //设置按钮的x
            childView.frame.origin.x = CGFloat(index) * childW
            //index递增
            index++
            //如果当前遍历到'发现',则把发现往后移动一个位置
            if index == 2 {
                index++
            }
        }
    }
}

  • 按钮监听
/// 定义闭包类型的属性
var composeButtonClosure: (()->())?

/// 在按钮点击的时候调用闭包
@objc private func composeButtonClick(){
    composeButtonClosure?()
}
  • 注意:按钮的监听方法不能使用 private,否则运行循环是找不到这个方法的,但是在这种情况下,如果不私有化的话,外界(控制器)可以直接调用这个方法,不符合设计思想,所以可以在加了private的情况下,可以用 @objc 去修饰这个方法

设置tabBar

因为tabBarController上的tabBar是只读属性,不能直接设置值,所以我们可以采用KVC的方式赋值:

let tab = HMTabBar()
//设置撰写按钮点击的事件响应
// 注意:此闭包内使用 `self` 会形成循环引用
tab.composeButtonClickBlock = {
    print("撰写按钮点击")
}
setValue(tab, forKey: "tabBar")

阶段性小结

  • 整体开发思路与使用 OC 几乎一致
  • Swift 语法更加简洁
  • Swift 对类型校验更加严格,不同类型的变量不允许直接计算
let w = tabBar.bounds.width / CGFloat(childViewControllers.count)
//设置按钮的宽
var frame = childView.frame
frame.size.width = childW
//设置按钮的x,此处index为Int类似的值
frame.origin.x = CGFloat(index) * childW
childView.frame = frame
  • Swift 中的懒加载本质上是一个闭包,因此引用当前控制器的对象时需要使用 self.
  • 不希望暴露的方法,应该使用 private 修饰符
    • 按钮点击事件的调用是由 运行循环 监听并且以消息机制传递的
    • 而Swift为了追求性能的这个特性决定了其在编译时期就已经决定好了某个事件该如何去调用
    • 而使用 private 修饰的方法在运行的时候对于运行循环是不可见的,所以会提示 找不到xxx方法
    • 可以使用 @objc 修饰此私有方法,其在于告诉系统此方法使用 Objective-C 的基于运行时的机制(KVC以及动态派发)
  • viewDidLoad 函数中添加子控制器只会完成控制器的添加,而不会为 tabBar 创建 tabBarButton

相关文章

网友评论

      本文标题:02-项目搭建

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