博客> StoryBoard 中级进阶教程
StoryBoard 中级进阶教程
2018-06-19 09:04 评论:0 阅读:653 virus1993

StoryBoard 中级进阶教程

说到 SB,很多人恨很多人爱,有的人又恨又爱。其实我觉得不是不舒服,而是很多人姿势不对。但是工作要求下很多人都放弃了尝试,要么纯代码,要么 SB 辅助存代码,当然这两种方法都很好,前者完全就是想象力的小黑屋,后者开发时就有点畏首畏尾生。

苹果每次都说 SB 好,肯定有它的道理,那么这里我们就探寻 SB 的无限可能性。

前言

SB 优势就是可视化,拖一拖,单车变摩托。但是问题也很明显,一旦要实现的不是图文展示,而是用户交互为主的,基本很多时候就GG了。 那么我们就不讨论它不能做什么,而是它能做什么,做到什么程度。

普通姿势

新建一个项目,默认 SB 里面只有一个 ViewController,我们打开右侧的 Identity Inspector,Class 选择 对应的视图控制器类,我们输入 MainViewController,如果没有 MainViewController,那么就新建一个吧。

图片

好的,回到SB,在 Object Library 里面拖 Navigation Controller 到场景中。

拖动场景中的 StoryBoard Entry Point 箭头到新加的 Navigation Controller 上,这里指明入口是 Navigation Controller,对应代码里面的sb.instantiateInitialViewController(), 取出来就是箭头指的那个视图控制器。

1

如果要取出系统自带的 ViewController,那么就使用如下代码:

let sb = UIStoryboard(name: "Main", bundle: Bundle.main)
let vc = sb.instantiateViewController(withIdentifier: "DefaultViewController") as! ViewController

Identifier 是在 SB 里面设置的 Identity Inspector 的 StoryBoard ID。

图片

拿到 UIViewController 你就可以自由的在代码里面翱翔了。 其实 Storyboard 就是将很多个 xib 和之间的关系放在一起,尽量可视化。 我们的第一反应是对试图控制器动手动脚,拖一拖,连一连,流程固定还好,流程不固定就是用代码上,因此接下来我给大家展示一种动态的混合流程控制。

中级姿势

在前面的基础上,我们知道默认 Navigation Controller 带一个 UITableViweController,那么我们要实现这一的列表,可以跳转到不同的视图中。

一般的做法是利用 UITableView 的代理方法 didSelectRowAt:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // 根据 indexPath 取数据再跳转到指定的页面
}

我们用 SB 的思维来做这个事情,首先修改 MainViewController 继承自 UITableViewController,然后到 SB 里面改 Navigation Controller 右边的视图控制器 Class 为 MainViewController。

选择 Prototype Cells,打开 Attribute Inspector,修改 Identifier 为 MainCell,用于重用,省下注册 cell 的机械代码的时间。不过也只是一行。

然后拖任何你想加入的试图控制器进来,我这里选择 3 个默认视图控制器:

拉线,指明当前页面可以跳转到三个页面,从 ViewController 拉线到视图控制器的页面,选择 Selection Segue 下的 Show 方式,分别修改 segue 线的 Identifier 为com.ascp.a、com.ascp.b、com.ascp.c:

图片

图片

看到这里你会觉得诧异,如果点击 cell 是不是会跳三个界面? 答案是:不会。

SB 鼓励的是一种流程的展示,也就是说将跳哪个页面不跳哪个页面要我们在代码里面控制,SB 表达的是有这么些个页面,这样操作会跳转到其它页面。

流程是需要完整的,流程是需要控制的,也就是代码来控制。

代码接管

剩下的事情就是代码控制了。

修改 MainViewController.swift 的代码,增加一个结构体 MenuItem,用来存储模型数据

struct MenuItem {
    /// 主标题
    var title : String
    /// 父标题
    var subtitle : String
    /// segue标识
    var segueIdentitfier : String
}

然后初始化数据,用一个变量存储列表项, 这里我们有三个页面,所以就添加三项, segueIdentitfier 要求和 SB 的严格一样。

class MainViewController: UITableViewController {
    var data = [MenuItem]()
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        let a = MenuItem(title: "A 页面", subtitle: "more a", segueIdentitfier: "com.ascp.a")
        let b = MenuItem(title: "B 页面", subtitle: "more b", segueIdentitfier: "com.ascp.b")
        let c = MenuItem(title: "C 页面", subtitle: "more c", segueIdentitfier: "com.ascp.c")
        data = [a, b, c]
    }
}

接着实现 UITableView 的数据代理,展示几组几列,以及样式,然后点击代理 didSelectRowAt 实现 performSegue(withIdentifier:sender:)方法执行页面跳转

extension MainViewController {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MainCell", for: indexPath)
        let item = data[indexPath.row]
        cell.textLabel?.text = item.title
        cell.detailTextLabel?.text = item.subtitle
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let item = data[indexPath.row]
        // 根据 indexPath 取数据再跳转到指定的页面
        performSegue(withIdentifier: item.segueIdentitfier, sender: nil)
    }
}

好了!,Command + R 跑起来!

讨论

代码里面无论是 A 视图控制器,还是其他页面,我们都不需要关心它是哪个 Class,只要指定 segueIdentitfier 就能实现指定的页面跳转,performSegue(withIdentifier:sender:)里面可以指定参数 sender 用来传值,总的来说确实省了很多机械代码,代码的灵活性很高,但是就是别人看你代码的话会崩溃,需要源码+SB来回切换看流程,因此文档就派上用场了(SB 不能注释,除非你喜欢 Source Code模式),

收藏
0
sina weixin mail 回到顶部