iOS界面开发—开篇

当前篇:iOS界面开发—开篇
下一篇:iOS界面开发—导航控制器和标签控制器

前言

本系列文章用来总结我自己做iOS开发的一些UI方面的经验,我从零开始跌跌撞撞做了三年iOS开发,能力有限,经验有限,如果有读者读到我的文章,有发现不对的地方,或者有更好的解决方法的地方,还望提出来一起讨论。

本系列文章不对开发语言进行讲解,代码用Swift4进行展示,同时不对UIKit框架的组件进行详细讲解。

我习惯用纯代码进行UI开发,因此文章里基本不会出现storyboard和xib,所以可能一些地方不适用于可视化界面开发,同时我很少用autolayout,我觉得手机屏幕尺寸固定有限,用代码布局妥妥的够了,也方便贴代码。

创建工程

首先创建一个UIStudy的工程,开发者账号及证书用你自己的就行,如果没有可以用虚拟机做测试,更改项目配置如下:

屏幕快照 2018-02-06 上午10.36.04.png

我们把Main Interface清空,表示不使用storyboard构建界面,现在编译应用可能会看到报错,提示safeArea在iOS 9.0之后才支持,可以把配置文件中的Deployment Target升到9.0,也可以在storyboard文件中把User Safe Area Layout Guides关掉

278DBDD7-DA03-4314-B635-2F9DF15C15E2.png

LaunchScreen.storyboard文件也一样,由于我们项目中没有用Main.storyboard来构建应用,所以可以选择删掉,但是LaunchScreen.storyboard文件暂时不能删掉,因为我们还需要用它来确保应用的窗口大小。

注意项目配置截图中Launch Images Source和Launch Screen File两个选项,它们是用来设置应用启动界面的,如果两个选项都没设置,那么应用可能不是全屏的,我们也可以用图片作为启动界面,需要给出每一种屏幕尺寸对应的图片,否则应用界面可能也不是全屏的,我们这里就不用图片了,就用LaunchScreen.storyboard文件作为启动界面就行了。

现在运行应用,我们看到的是一个黑框,如果需要显示图形界面,就需要手动创建了,这就是为什么我不用Main.storyboard的原因,因为不写代码可能不会知道应用的界面是怎么显示出来的。

手动显示界面

如果我们要让应用正常显示图形界面,就需要自己动手创建,核心就在于UIWindow。想要显示一个图形界面就需要创建一个 UIWindow ,设置rootViewController,然后让其成为主窗口:

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    window = UIWindow.init(frame: UIScreen.main.bounds)
    window!.backgroundColor = UIColor.white
    window!.rootViewController = ViewController()
    window!.makeKeyAndVisible()
    return true
}

打开AppDelegate.swift编写以上代码,运行应用,我们就能看见一个白色的界面了,这个界面的内容就是ViewController中定义的内容,现在还是空的界面,稍候我们会在上面显示一些内容。

创建UIWindow时一定要指定frame,否则在iOS 8及以上系统中应用无法响应事件,同时最好设置一下背景色,否则可能会在某些极其特殊的情况下屏幕中间会出现黑块。

简单布局扩展

import UIKit

//MARK: 简单布局扩展
extension UIView {
    
    //MARK: iPhone X适配属性
    
    /** 高度减去iPhone X底部不安全高度*/
    var safeAreaBottom: CGFloat {
        if #available(iOS 11.0, *) {
            return height - safeAreaInsets.bottom
        } else {
            return height
        }
    }
    
    /** iPhone X顶部不安全高度*/
    var safeAreaTop: CGFloat {
        if #available(iOS 11.0, *) {
            return safeAreaInsets.top
        } else {
            return 0
        }
    }
    
    /** iPhone X安全区域高度*/
    var safeAreaHeight: CGFloat {
        if #available(iOS 11.0, *) {
            return height - safeAreaInsets.bottom - safeAreaInsets.top
        } else {
            return height
        }
    }
    
    var height: CGFloat {
        get {
            return self.frame.size.height
        }
        set {
            self.frame.size.height = newValue
        }
    }
    
    var width: CGFloat {
        get {
            return self.frame.size.width
        }
        set {
            self.frame.size.width = newValue
        }
    }
    
    var size: CGSize {
        get {
            return self.frame.size
        }
        set {
            self.frame.size = newValue
        }
    }
    
    var top: CGFloat {
        get {
            return self.frame.origin.y
        }
        set {
            self.frame.origin.y = newValue
        }
    }
    
    var bottom: CGFloat {
        get {
            return self.top + self.height
        }
        set {
            self.frame.origin.y = newValue - self.height
        }
    }
    
    var left: CGFloat {
        get {
            return self.frame.origin.x
        }
        set {
            self.frame.origin.x = newValue
        }
    }
    
    var right: CGFloat {
        get {
            return self.left + self.width
        }
        set {
            self.frame.origin.x = newValue - self.width
        }
    }
    
    var origin: CGPoint {
        get {
            return self.frame.origin
        }
        set {
            self.frame.origin = newValue
        }
    }
    
    var centerX: CGFloat {
        get {
            return self.center.x
        }
        set {
            self.center.x = newValue
        }
    }
    
    var centerY: CGFloat {
        get {
            return self.center.y
        }
        set {
            self.center.y = newValue
        }
    }
    
    //MARK: 适应性布局设置
    //例如:当改变left位置的时候,自适应宽度好保持视图right位置不变
    
    func autoLeft(_ new: CGFloat) {
        let widthChanged = left - new
        left = new
        width += widthChanged
    }
    
    func autoRight(_ new: CGFloat) {
        let widthChanged = right - new
        width -= widthChanged
    }
    
    func autoTop(_ new: CGFloat) {
        let heightChanged = top - new
        top = new
        height += heightChanged
    }
    
    func autoBottom(_ new: CGFloat) {
        let heightChanged = bottom - new
        height -= heightChanged
    }
    
}

请将上面代码写进项目中,方便我们在设置frame时更好的理解布局的意图,可以像我这样组织代码文件:

屏幕快照 2018-02-06 上午11.48.48.png

Hello World

下面我们在界面中显示一串Hello World,打开ViewController.swift文件编写代码:

import UIKit

class ViewController: UIViewController {
    
    let label = UILabel()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(label)
        label.text = "Hello World"
        label.sizeToFit()
    }

    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        label.centerX = view.width / 2
        label.centerY = view.height / 2
    }

}

手动布局的套路就是,在viewDidLoad方法中添加子视图,在viewWillLayoutSubviews方法中设置子视图位置,在viewDidLoad方法中获取view.frame是不准确的。使用viewWillLayoutSubviews或者layoutSubviews方法需要注意的就是在UIScrollView中,滑动事件也会触发布局方法,在滑动的时候不要去设置子视图位置。

运行应用,界面中央出现了一串大大的Hello World字样。

以上就是创建一个应用,显示一个图形界面,以及自定义图形界面内容的全过程,后面的UI开发都是基于此,无非就是把ViewController换成UITabBarController,UINavigationController而已。

当前篇:iOS界面开发—开篇
下一篇:iOS界面开发—导航控制器和标签控制器

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

推荐阅读更多精彩内容