原文作者:Cooci https://www.jianshu.com/p/4dca6e64ef15?tdsourcetag=s_pcqq_aiomsg
创建和组合视图
- 本篇文章将通过一个构建应用(
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 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()
}
}
第六步
添加阴影。
第七步
将边框颜色更改为白色。
代码语言:javascript复制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协议
。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) 。
整体写下来,就是感觉很简单,很舒服.更加快速的面向开发,此时此刻还有谁! Swift 写天写地写世界,千秋万载,一统江湖