[iOS UI] 显示

概述

在所有拥有UI的系统开发工作中,一般开发人员最先认识的都是UI系统,这也是在自然界人们认知事物的习惯-从表及里的认知过程。

从我个人的经验出发,包括iOS,Android,Qt等完成一个App UI开发,总结来都可以从下图3个部分来完成,那么要系统地掌握一个系统UI开发过程和其中的问题,都可以从这3个方面来认知和展开。

程序UI完成步骤

这篇文章,主要探讨一下第一部分- view显示

问题和结论

view显示

如图 view显示,关于这个主题我们需要搞清楚两件事情(并给出结论):

  1. iOS界面显示到底是什么在显示?

UIView的层级结构显示

  1. 具体是通过什么方式显示
  • 通过UIViewController进行UIView管理并显示
  • 通过代码
  • nib file
  • storyboard
  • 直接对UIWindow进行addSubView的操作(实际开发中不这么做)

解析

问题1

我们首先看看显示一个简单的“hello view”需要做哪些工作。在Xcode中创建一个Single View Application,打开Main.storyboard,在右下角的Object Library中拖一个Label到Main.storyboard的画布中(靠近左上角放置),修改Label的文字“hello view”,运行,就会看到我们想要的界面。
程序在模拟器中运行起来之后,在Xcode中选择Debug View Hierarchy,回看到如下图的app view 3d渲染: 我们可以看到实际上组成界面的是UIWindow->UIView->UILabel

view hierarchy.png

因为iOS是通过UIScreen类拿到硬件屏幕显示,所以事实上,UIWindow是添加到UIScreen上以最终显示,所以完整的结构是下图所示(撒懒网上找得图哈)

网图

问题2

window.addSubView

验证问题1所展示的例子,是使用storyboard完成的,在代码层具体做了些什么,Interface Builder替我们完成了。这一节我们来探究代码实现。
新建一个Single View Application,打开AppDelegate.swift(OC相应代码很容易参照完成),修改第一个方法如下代码示例1:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        var text = UILabel(frame: CGRectMake(20, 20, 100, 50))
        text.backgroundColor = UIColor.greenColor()
        text.text = "Hello World"
        window?.addSubview(text)
        window?.makeKeyAndVisible()
        
        return true
    }

运行,结果如下图:


addSubView.png

可以看到,同样达到了显示一个UILabel到屏幕上的结果,我们可以删除Main.storyboard以证明是我们的代码得到了这样的结果(当然这不是必要的)。
查看注释非常容易理解上面程序做得事:

创建一个UIWindow占满整个UIScreen,然后创建了一个UILabel,把它加到UIWindow,最后把UIWindow设置为主Window并显示。

通过ViewController

通过代码

虽然这样能把UIView显示在屏幕上,并且也可以构建复杂的View hierarchy,但是这是Apple不推荐的,整个iOS开发推荐的管理界面的方法是使用ViewController。
咱们对上面的代码进行修改,把整个方法修改为如下代码示例2:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        var text = UILabel(frame: CGRectMake(20, 20, 100, 50))
        text.backgroundColor = UIColor.greenColor()
        text.text = "Hello World"
        var vc = UIViewController()
        vc.view.addSubview(text)
        window?.rootViewController = vc
        window?.makeKeyAndVisible()
        
        return true
    }

运行程序,得到和addSubView.png一样的效果

主要的改动就是引入了UIViewController并把ViewController设置为window.rootViewController,而本来直接加入window子view的UILabel,被UIViewController的View管理起来

在现实开发中,ViewController要控制View显示的方方面面,加载,修改,布局等等,所以,代码示例2在这里创建UIViewController并进行View的组装仅仅是为了易于理解,真正的开发中,代码实现界面显示会是如下的做法:
下图是Xcode Single View Application默认的工程结构,


default project structure.png

打开ViewController.swift,覆盖loadView()方法,修改完的代码示例如下:

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func loadView() {
        
        let v = UIView()
        self.view = v
        
        let label = UILabel(frame: CGRectMake(20, 20, 100, 50))
        label.backgroundColor = UIColor.greenColor()
        label.text = "hello world"
        v.addSubview(label)
    }
}

然后我们得修改AppDelegate的第一个方法如下代码示例:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        window?.rootViewController = ViewController()
        window?.makeKeyAndVisible()
        
        return true
    }

运行程序,还是会得到addSubView.png一样的效果

除了代码创建UI外,iOS还提供了两种方式来所见即所得地创建UI,storyboard和nib file,两者其实都是本地化存储的iOS对象,在运行时加载组装和代码一起完成UI的构建和显示,现在storyboard是Xcode默认方式,我们从它看起。

storyboard

新建一个Single View Application,给storyboard中加入一个UILabel “hello world",然后修改AppDelegate.swift第一个方法如下代码示例:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        var mainSb = UIStoryboard(name: "Main", bundle: nil)
        window?.rootViewController = mainSb.instantiateInitialViewController() as? UIViewController
        window?.makeKeyAndVisible()
        
        return true
    }

运行工程,会得到跟没有修改AppDelegate.swift之前一样的结果。其实,这就是默认Single View Application隐性为我们做得事:

加载storyboard,从storyboard中加载initial View Controller,并把initial View Controller设置为window的rootViewController

nib file

新建一个Single View Application,新建一个User Interface -> View, 命名MainNib,创建完成会生成一个MainNib.xib。选中MainNib.xib,点击View上面的File’s Owner,然后在右侧Identity Inspector中Custom Class的Class框里填上工程生成的ViewController。再选择最右边的Connection Inspector,将Outlets下面的View拖向画布(也就是UIView),将ViewController的View和MainNib.xib中的View进行连接。拖一个“Hello World” UILabel到画布中。


add file's owner.png

connect outlets.png

然后修改AppDelegate.swift的第一个方法为如下代码:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        
        window = UIWindow(frame: UIScreen.mainScreen().bounds)
        window?.rootViewController = ViewController(nibName: "MainNib", bundle: nil)
        window?.makeKeyAndVisible()
        
        return true
    }

运行程序,会看到和用storyboard相同的结果。


至此,UI显示入门就告一段落。当然这里并没有深入涉及UIView的相关内容,这在以后的博客中会有所涉及。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容