SwiftUI只支持Xcode 十一、iOS 13版本及以上。git
官方文档连接:developer.apple.com/tutorials/s…编程
本篇文章将经过一个构建应用(Landmarks,一个能够发现、分享你喜欢地点的App)示例,来引导你们进行SwiftUI开发。咱们将使用SwiftUI框架来构建Landmark详情界面。swift
Landmarks利用stacks将图片和文本组合起来来进行视图布局。你须要引用MapKit框架头文件来建立一个地图视图。 你能够经过Xcode新的实时反馈功能,来优化你的视图布局 。bash
1.下载Demo工程。
2.下载Xcode11 Beta。app
利用SwiftUI应用模版来建立工程,而后探索了解下SwiftUI的画布。框架
为了可以体验Xcode 11的view实时预览和交互功能,必定要确保你的mac系统版本是macOS 10.15 beta。编辑器
打开 Xcode->Create a new Xcode project,或者经过File > New > Project 来建立工程。ide
在模版选择区域,选择 iOS->Single View App->Next 。工具
输入项目名称 Landmarks->勾选Use SwiftUI->Next 保存。布局
在Xcode导航栏,建立ContentView.swift。一般SwiftUI会声明两个结构体。第一个结构体继承自View,而且在这儿进行View的布局。第二个结构体声明了一个ContentView 的preview,继承自PreviewProvider。
感谢@SoolyChristina基友的友情提示。这儿并不是是继承的概念,原文的描述以下: The first structure conforms to the View protocol and describes the view’s content and layout. The second structure declares a preview for that view.
因此这儿声明的两个结构体,更像是遵循了View和PreviewProvider协议。
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello World")
}
}
struct ContentView_Preview: PreviewProvider {
static var previews: some View {
ContentView()
}
}
复制代码
在SwiftUI画布中点击 Resume 进行视图预览。
Tip:若是画布没有展现出来,能够经过 Editor > Editor and Canvas 显示出来。
把Hello World更改成Hello SwiftUI!
当你修改文案后,SwiftUI会自动更新视图。(这他么不就是热重载嘛 Hot-Reload )
你有两种方式来自定义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修改自动更新你的代码。
咱们建立了一个文本框用来显示landmark的详情信息,而且把这个文本控件放到头部。
当咱们建立SwiftUI视图控件的时候,咱们会把控件的内容、布局还有一些行为放在body属性中;然而body属性只返回了一个view。你能够利用stacks嵌入多个view,它能够垂直嵌入、水平嵌入等。
在这个篇幅,咱们将使用垂直stack来显示park详情信息。
Command+点按text初始化方法区域。选择 Embed in VStack 。
接下来,咱们将拖拽一个text view到stack中。
点击+号,打开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())方法,建立圆形视图。
再建立一个圆圈,用灰色进行填充。并将它做为image的border。
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()
}
}
复制代码
如今咱们须要建立一个地图视图。你能够MapKit中的MKMapView类来展现渲染地图界面。
在SwiftUI中要使用UIView或者其子类,你须要让你的view遵循UIViewRepresentable协议。SwiftUI在WatchKit和AppKit一样声明了相似的协议。
建立新的SwiftUI View来展现MKMapView。 File > 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视图控件。由于MKMapView是UIView子类,因此你须要把模式切换成live模式才能正常预览。
点击 Live Preview 切换预览模式。
如今咱们已经把全部子控件定义实现好了。
利用咱们现有的工具,咱们能够把这些子控件组合起来,造成完整的landmarks详情界面。
在工程导航区,选择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的上面。设置MapView的frame。
若是你只设置了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) 。