导航栏设置
课程目标
- 便利构造函数的使用
- 自定义显示到 XIB 控制面板的属性
- 自定义导航控制器思路
发现页面搜索框
课程目标
- 明确 Xib 创建视图的流程
- IBInspectable&IBDesignable使用
代码实现
- 新建
HMDiscoverSearchView
继承于UIView
class HMDiscoverSearchView: UIView,UITextFieldDelegate {
}
- 新建 Xib 文件
HMDiscoverSearchView.xib
- 拖入
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 里面渲染
图片填充模式
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进入的控制器都会经过
UINavigationController
的pushViewController(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控制器的时候,顶部右边会出现部分阴影:
解决方法:
// 给tabBar(或者navigationBar)设置一张背景图片
// HMMainViewController->ViewDidLoad()方法里面
let tab = HMTabBar()
// 设置撰写按钮点击的事件响应
tab.composeButtonClickBlock = {
print("撰写按钮点击")
}
// 设置背景图片,去掉顶部阴影的效果
tab.backgroundImage = UIImage(named: "tabbar_background")
setValue(tab, forKey: "tabBar")