03-导航栏设置

导航栏设置

课程目标

  • 便利构造函数的使用
  • 自定义显示到 XIB 控制面板的属性
  • 自定义导航控制器思路

发现页面搜索框

课程目标

  • 明确 Xib 创建视图的流程
  • IBInspectable&IBDesignable使用

代码实现

  • 新建 HMDiscoverSearchView 继承于 UIView
class HMDiscoverSearchView: UIView,UITextFieldDelegate {

}
  • 新建 Xib 文件 HMDiscoverSearchView.xib
  1. 拖入 UITextField 作输入框
  • 拖入 UIButton 作取消按钮
  • 添加相关约束
  • 指定 class 为 HMDiscoverSearchView
  • 连线
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var cancelButton: UIButton!
  • HMDiscoverSearchView 提供类方法通过 xib 创建 view
class func searchView() -> HMDiscoverSearchView {
    let view = NSBundle.mainBundle().loadNibNamed("HMDiscoverSearchView", owner: nil, options: nil).last! as! HMDiscoverSearchView
    return view;
}
  • HMDiscoverTableViewController 添加方法,测试此View的显示
private func setupUI(){
    let searchView = HMDiscoverSearchView.searchView()
    searchView.frame = CGRectMake(0, 0, UIScreen.mainScreen().bounds.size.width, 35)
    navigationItem.titleView = searchView
}
  • 设置 textfield 的左边放大镜视图
private lazy var leftImage: UIImageView = {
    return UIImageView(image: UIImage(named: "searchbar_textfield_search_icon")!)
}()

...
override func awakeFromNib() {
    // 设置 textField 的左边视图
    leftImage.frame = CGRectMake(0, 0, frame.height, frame.height)
    leftImage.contentMode = .Center
    textField.leftView = leftImage
    // 设置显示模型
    textField.leftViewMode = UITextFieldViewMode.Always
}
  • 设置 textField 的代理,实现代理方法
class HMDiscoverSearchView: UIView,UITextFieldDelegate {
    ...

    func textFieldDidBeginEditing(textField: UITextField) {

    }
}

  • 拖入 textfield 右边的约束到 view 中,在开始编辑的时候执行动画
@IBOutlet weak var textFieldRightCons: NSLayoutConstraint!
  • 执行约束动画需要调用 view 的 layoutIfNeed
func textFieldDidBeginEditing(textField: UITextField) {
    textFieldRightCons.constant = cancelButton.frame.width
    // 执行动画
    UIView.animateWithDuration(0.25) { () -> Void in
        self.textField.layoutIfNeeded()
    }
}
  • 拖入取消按钮的点击事件,点击的时候取消第一响应者并执行动画
@IBAction func cancelButtonClick(sender: UIButton) {
    textField.resignFirstResponder()
    textFieldRightCons.constant = 0

    // 执行动画
    UIView.animateWithDuration(0.25) { () -> Void in
        self.textField.layoutIfNeeded()
    }
}

IBInspectable & IBDesignable

IBInspectable

  • 其修饰的属性可以在 XIB/SB 右边控制面板显示
  • 可以重写该属性的 get/set 方法做自己的操作

IBDesignable

  • 其修饰自定义 View
  • 可以在更改 IBInspectable 修饰的属性的时候动态在 XIB/SB 里面渲染

图片填充模式

03-导航栏设置_第1张图片
图片填充模式.png

UIBarButtonItem抽取

  • 快速构造一个 UIBarButtonItem
// item 上的文字颜色,高亮颜色,字体大小
// 导航栏上左右的文字一般都会统一,所以可以定义成常量
private let ItemNormalColor = UIColor(red: 80/255, green: 80/255, blue: 80/255, alpha: 1)
private let ItemHighlightedColor = UIColor.orangeColor()
private let ItemFontSize: CGFloat = 14

extension UIBarButtonItem {

    /// 快速构造一个 UIBarButtonItem
    ///
    /// - parameter imgName: 图片名字
    /// - parameter title:   标题文字
    /// - parameter target:
    /// - parameter action:
    ///
    /// - returns: UIBarButtonItem
    convenience init(imgName: String? = nil,title: String? = nil, target: AnyObject?, action: Selector){
        self.init()

        let button = UIButton()
        button.addTarget(target, action: action, forControlEvents: .TouchUpInside)

        // 如果有图片,设置图片
        if let img = imgName {
            button.setImage(UIImage(named: img), forState: UIControlState.Normal)
            button.setImage(UIImage(named: "\(img)_highlighted"), forState: UIControlState.Highlighted)
        }

        // 如果有文字,设置文字
        if let t = title {
            button.setTitle(t, forState: UIControlState.Normal)
            button.titleLabel?.font = UIFont.systemFontOfSize(ItemFontSize)
            button.setTitleColor(UIColor(red: 80/255, green: 80/255, blue: 80/255, alpha: 1), forState: .Normal)
            button.setTitleColor(UIColor.orangeColor(), forState: .Highlighted)
        }
        button.sizeToFit()

        customView = button

    }
}

自定义导航控制器

课程目标

自定义 UINavigationController,实现新浪微博左上角返回按钮逻辑

  • 如果是从一级页面进入到二级页面,第二级页面左上角返回按钮显示一级页面的title
  • 如果是从二级页面进入到三级页面(或者层次更深),进入页面的左上角返回按钮显示返回

分析

  • 如果要在每一个控制器里面分别设置的话,代码烦琐而且扩展性不强,所以写一个自己的 UINavigationController
  • 新push进入的控制器都会经过 UINavigationControllerpushViewController(viewController: UIViewController, animated: Bool) 方法
  • 可以在这个方法里面判断当前是 push 进入的是第几级控制器,并设置不同的返回按钮title

代码

import UIKit

class HMNavigationController: UINavigationController {

    /**
    重写此方法,在里面统一返回按钮逻辑

    - parameter viewController: 将要push进来的控制器
    - parameter animated:       是否需要动画
    */
    override func pushViewController(viewController: UIViewController, animated: Bool) {

        // 如果当前里面有控制器,才执行下面的逻辑
        if childViewControllers.count > 0 {

            var title = "返回"

            if childViewControllers.count == 1 {
                //正要往里面添加第二个控制器
                title = childViewControllers.first?.title ?? "返回"
            }
            // push第二个或者以后控制器隐藏底部tabBar
            viewController.hidesBottomBarWhenPushed = true
            // 设置左边item
            viewController.navigationItem.leftBarButtonItem = UIBarButtonItem(imgName: "navigationbar_back_withtext", title: title, target: self, action: "back")

        }
        super.pushViewController(viewController, animated: animated)
    }

    @objc private func back(){
        popViewControllerAnimated(true)
    }
}

在 HMMainViewController 添加子控制器的地方,使用自己定义的导航控制器

  • 默认push控制器的时候,顶部右边会出现部分阴影:
03-导航栏设置_第2张图片
navigationBar-bug.png

解决方法:

// 给tabBar(或者navigationBar)设置一张背景图片
// HMMainViewController->ViewDidLoad()方法里面
let tab = HMTabBar()
// 设置撰写按钮点击的事件响应
tab.composeButtonClickBlock = {
    print("撰写按钮点击")
}
// 设置背景图片,去掉顶部阴影的效果
tab.backgroundImage = UIImage(named: "tabbar_background")
setValue(tab, forKey: "tabBar")

你可能感兴趣的:(03-导航栏设置)