WWDC - SwiftUI - 初恋般的感觉

*SwiftUI is a modern way to declare user interfaces for any Apple platform. Create beautiful, dynamic apps faster than ever before.

一种牛逼的更加快速,更加漂亮的用户界面的方法

创建和组合视图

  • 本篇文章将通过一个构建应用(Landmarks,一个可以发现、分享你喜欢地点的App)示例,来引导大家进行SwiftUI开发。我们将使用SwiftUI框架来构建Landmark详情界面。
  • Landmarks利用stacks将图片和文本组合起来来进行视图布局。你需要引用MapKit框架头文件来创建一个地图视图。 你可以通过Xcode新的实时反馈功能,来优化你的视图布局 。

创建一个使用SwiftUI的新Xcode项目。浏览画布、预览和SwiftUI模板代码。

要在Xcode中预览画布上的视图并与之交互,请确保您的Mac运行的是macOS 10.15 beta版

macOS 10.15 beta版下载地址
Xcode 11下载地址

第一步

  • 打开 Xcode->Create a new Xcode project,或者通过File > New > Project 来创建工程。

第二步

  • 在模版选择区域,选择 iOS->Single View App->Next 。

第三步

  • 输入项目名称 LGSwiftUIDemo->勾选Use SwiftUI->Next 保存。
    记得一定要选择语言:Swift 然后勾选 Use SwiftUI

点击之后你就会感觉发现了新东西咯:

  • 左边没有了ViewController 多了sceneDelegate和ContentView
  • 中间代码样式不一样了
  • 右边多出一块预显示栏,很牛逼

默认情况下,SwiftUI视图文件声明两个结构。

  • 第一个结构符合视图协议,描述了视图的内容和布局。
  • 第二个结构声明了该视图的预览。

现在我们来玩玩预览:

如果画布没有展示出来,可以通过 Editor > Editor and Canvas 显示出来。

第四步

把Hello World更改为Hello SwiftUI!
当你修改文案后,SwiftUI会自动更新视图。


自定义Text View

你有两种方式来自定义TextView

  • 第一种方式是直接修改view代码
  • 第二种方式是通过inspector检查器来帮助你进行代码编写。

当你构建Landmarks的时候,你可以运用任何一个编辑器来进行编码工作:直接修改源代码、通过画布、通过inspector view检查器。代码并不会关心你用什么工具,它始终能够保持最新状态

接下来,你将通过inspector来自定义Text View

第一步

  • preview画布上,按住Command键+点按Text文本框,这时候inspector就会被唤起。
    inspector弹出框所展示的属性也会因为不同的UI控件而有所不同。

第二步

通过inspector检查器修改Text文本框的属性。

第三步

  • 修改文本框字体。
  • 修改文本框字体是利用的系统的字体。

第四步

  • 手动修改代码,即添加.color(.green)把文本修改成绿色。
  • 要自定义SwiftUI视图,你可以调用modifiers方法。Modifiers可以修改视图的属性,并且modifier返回一个新的视图,所以通常会将多个modifiers像链一样垂直堆叠在一起。( 链式编程)。
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Turtle Rock")
            .font(.title)
            .color(.green)
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

你编写的代码肯定和view是一一对应的。当你通过inspector修改了view属性之后,Xcode会自动更新你的代码。

第五步

这时候,打开inspector,然后把文本Color属性修改为Inherited。

第六步

注意一点的就是,Xcode会根据inspector修改自动更新你的代码。

利用Stacks组合视图

我们创建了一个文本框用来显示landmark的详情信息,并且把这个文本控件放到头部。
当我们创建SwiftUI视图控件的时候,我们会把控件的内容、布局还有一些行为放在body属性中;然而body属性只返回了一个view。你可以利用stacks嵌入多个view,它可以垂直嵌入、水平嵌入等。
在这里,我们将使用垂直stack来显示park详情信息

第一步

Command+点按text初始化方法区域。选择Embed in VStack

第二步

  • 接下来,我们将拖拽一个text viewstack中。
  • 点击+号,打开Library面板。拖拽一个text view到 “Turtle Rock”后面 。

第三步

修改text view文案为Joshua Tree National Park

第四步

设置text view的字体。

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Turtle Rock")
                .font(.title)
            Text("Joshua Tree National Park")
                .font(.subheadline)
        }
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

第五步

修改VStack对齐方式。


import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Turtle Rock")
                .font(.title)
            Text("Joshua Tree National Park")
                .font(.subheadline)
        }
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

如果不设置对齐方式,VStack默认是内容垂直居中。

第六步

在面板中,Command+点按 Joshua Tree National Park唤起inspector,选择Embed in HStack

第七步

location后面添加一个新的文本框,修改文本框文案并设置字体


import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Turtle Rock")
                .font(.title)
            HStack {
                Text("Joshua Tree National Park")
                    .font(.subheadline)
                Text("California")
                    .font(.subheadline)
            }
        }
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

第八步

  • 可以在两个水平的文本框之间添加Space来适应宽度。
  • Space把父视图在水平或者垂直方向上全部充满。

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Turtle Rock")
                .font(.title)
            HStack {
                Text("Joshua Tree National Park")
                    .font(.subheadline)
                Spacer()
                Text("California")
                    .font(.subheadline)
            }
        }
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

第九步

最后,利用padding()来设置边距。


import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Turtle Rock")
                .font(.title)
            HStack {
                Text("Joshua Tree National Park")
                    .font(.subheadline)
                Spacer()
                Text("California")
                    .font(.subheadline)
            }
        }
        .padding()
    }
}

struct ContentView_Preview: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

创建一个自定义的图片视图

我们已经把park名称和位置的视图做好了,接下来我们将给park添加个图片。
你不需要添加很多代码,就可以添加一个带mask、border、shadow的图片。

第一步

添加一张图片到asset catalog中。
Resource文件夹中找到turtlerock.png图片,然后把它拖拽到asset catalog中。

第二步

选择File > New > File打开模版选择面板。在 User Interface区域,选择 SwiftUI View->Next ,命名为CircleImage.swift

第三步

Text构建方法替换成Image

import SwiftUI

struct CircleImage: View {
    var body: some View {
        Image("turtlerock")
    }
}

struct CircleImage_Preview: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}

第四步

调用.clipShape(Circle())方法,创建圆形视图。

第五步

再创建一个圆圈,用灰色进行填充。并将它作为imageborder

import SwiftUI

struct CircleImage: View {
    var body: some View {
        Image("turtlerock")
            .clipShape(Circle())
            .overlay(
                Circle().stroke(Color.gray, lineWidth: 4))
    }
}

struct CircleImage_Preview: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}

第六步

添加阴影。

第七步

将边框颜色更改为白色。

import SwiftUI

struct CircleImage: View {
    var body: some View {
        Image("turtlerock")
            .clipShape(Circle())
            .overlay(
                Circle().stroke(Color.white, lineWidth: 4))
            .shadow(radius: 10)
    }
}

struct CircleImage_Preview: PreviewProvider {
    static var previews: some View {
        CircleImage()
    }
}

UIKit和SwiftUI混合使用

现在我们需要创建一个地图视图。你可以MapKit中的MKMapView类来展示渲染地图界面。
SwiftUI中要使用UIView或者其子类,你需要让你的view遵循UIViewRepresentable协议SwiftUIWatchKitAppKit同样声明了类似的协议

第一步

创建新的SwiftUI View来展示MKMapViewFile > New > File,然后创建MapView.swift

第二步

引入MapKit头文件,并且让MapView遵循UIViewRepresentable协议。

第三步

UIViewRepresentable协议有两个协议方法需要实现。第一是UIView(context:)来创建MKMapView。第二个updateUIView(_:context:)来更新view
body属性干掉,然后UIView(context:)协议方法来创建MKMapView

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        MKMapView(frame: .zero)
    }
}

struct MapView_Preview: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

第四步

实现updateUIView(_:context:)协议方法,来更新view(设置地图经纬度等)。

func updateUIView(_ view: MKMapView, context: Context) {
        let coordinate = CLLocationCoordinate2D(
            latitude: 34.011286, longitude: -116.166868)
        let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
        let region = MKCoordinateRegion(center: coordinate, span: span)
        view.setRegion(region, animated: true)
}

第五步

当在静态模式下进行预览的时候,Xcode只能渲染SwiftUI视图控件。因为MKMapViewUIView子类,所以你需要把模式切换成live模式才能正常预览。
点击Live Preview切换预览模式。

把上面的子控件组合成一个完成的详情界面

现在我们已经把所有子控件定义实现好了。
利用我们现有的工具,我们可以把这些子控件组合起来,形成完整的landmarks详情界面。

image.png

第一步

在工程导航区,选择ContentView.swift文件。

第二步

在这三个text view控件外面,再嵌入一个VStack视图。

struct ContentView: View {
    var body: some View {
        VStack {
            VStack(alignment: .leading) {
                Text("Turtle Rock")
                    .font(.title)
                HStack(alignment: .top) {
                    Text("Joshua Tree National Park")
                        .font(.subheadline)
                    Spacer()
                    Text("California")
                        .font(.subheadline)
                }
            }
            .padding()
        }
    }
}

第三步

将你自定义的MapView放在stack的上面。设置MapViewframe
如果你只设置了Mapview的高度,那么MapView会自动设置其宽度来适应父视图。所以MapView会充满宽度区域。

struct ContentView: View {
    var body: some View {
        VStack {
            MapView()
                .frame(height: 300)

            VStack(alignment: .leading) {
                Text("Turtle Rock")
                    .font(.title)
                HStack(alignment: .top) {
                    Text("Joshua Tree National Park")
                        .font(.subheadline)
                    Spacer()
                    Text("California")
                        .font(.subheadline)
                }
            }
            .padding()
        }
    }
}

第四步

点击Live Preview来预览效果。
预览状态下,你可以继续编写view的代码,Live Preview会实时更新视图。

第五步

CircleImage添加到stack上面。

struct ContentView: View {
    var body: some View {
        VStack {
            MapView()
                .frame(height: 300)

            CircleImage()

            VStack(alignment: .leading) {
                Text("Turtle Rock")
                    .font(.title)
                HStack(alignment: .top) {
                    Text("Joshua Tree National Park")
                        .font(.subheadline)
                    Spacer()
                    Text("California")
                        .font(.subheadline)
                }
            }
            .padding()
        }
    }
}

第六步

调整一下Image的偏移。

第七步

VStack的底部添加spacer占位。

第八步

最后设置下 edgesIgnoringSafeArea(.top) 。

整体写下来,就是感觉很简单,很舒服.更加快速的面向开发,此时此刻还有谁!
Swift 写天写地写世界,千秋万载,一统江湖

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

推荐阅读更多精彩内容