SwiftUI一创建和组合视图

代码下载

创建新项目

要想在Xcode中预览画布中的视图或者与画布中的视图进行交互,要求Mac系统版本号不低于macOS Catalina 10.15

  • 打开Xcode,在启动页面点击创建新工程或者在菜单中选择文件->新建->项目
  • 在项目模板选择器中,选择iOS作为项目平台,选项单视图应用(Single View App)作为项目模板,并点击下一步(Next)
  • 输入项目名称,选择SwiftUI作为用户界面的创建方式,并点击下一步(Next),在磁盘目录下选择一个位置用来存放新创建的工程项目

工程创建好并打开后,在文件导航器中,选择ContentView.swift文件,可以浏览一下SwiftUI视图的组成结构。默认情况下,SwiftUI的视图文件包含两个结构体(Struct) 第一个结构体遵循View协议,描述视图的内容和布局。第二个结构体声明为第一个视图的预览视图,Xcode15 将此结构图更改为 #Preview

画布(Canvas)上,点击恢复(Resume)按钮可以显示预览视图,也可以使用快捷键Command+Option+P

在body属性内部,修改文字Hello World为其它的不同的文字,当你在改变代码的同时,预览视图也会实时的更新对应的内容变化

定制文本视图(Text View)

可以通过修改代码来改变一个视图的显示样式,也可以通过检查器获取视图可修改属性,然后再写对应的代码改变样式。在创建应用的过程中,可以同时使用源码编辑器、画布或者检查器,无论当前使用的是哪一个工具编辑视图,代码会保持和这些编辑器展示的样式一致

使用检查器来定制视图的显示样式

在代码中右键点击控件单词,会弹出一个编辑弹层,然后选择检查器(Inspect), 编辑弹层显示所有可以定制的视图属性,选中的控件不同,可以定制的属性集合也不相同

使用检查器把文字更改为Turtle Rock,改变字体修改器为Title

定制SwiftUI视图所调用的方法被称为视图修改器(Modifiers),修改器在原视图的基础上修改部分显示样式和属性,返回一个新的视图,这样就可以让多个修改器串连进行,形成水平方向的链式调用,或者垂直方向的堆叠调用

手动在代码中添加foregroundColor(.green) 属性修改器,就会把文字的颜色调整为绿色。代码是决定视图样式的根本,当我们使用检查器来改变或移除一个属性修改器时,Xcode也会在代码编辑器中同步改变或移除对应的修改器代码

从检查器中点击Color弹出菜单,选择继承(Inherited),让文字的颜色恢复成原来的黑色,Xcode会自动更新你的代码来反映视图的实际显示状况

使用栈来组合视图

创建SwiftUI视图就是在body属性中描述视图的内容、布局及行为,但body属性只返回单个视图,这时组合多个视图时可以把它们放入一个栈中,通过水平、垂直、前后嵌套多个视图完成视图组合,做为一个整体在body属性中返回

  • 双击Text视图的初始化代码打开结构化编辑弹窗,然后选择把控件嵌套在垂直栈中(Embed in VStack),在栈中添加Text View控件可以从组件中直接拖进栈中完成
  • 点击Xcode右上角的+号,托动一个Text控件到指定位置,代码立即就会在编辑器中补全
  • 把Text视图的占位文本修改为Joshua Tree Nation Park,视图会自动调整位置布局
  • 设置位置控件的字体为子标题样式
  • 设置VStack初始化参数为左对齐内部的子视图。默认情况下,栈会把内部视图在自己的主轴上居中对齐,并自动计算各子视图的间距。下一步要添加一个Text控制用来描述公园的状态,它水平排列在位置信息的右边。
  • 在弹出的菜单中选择嵌入到水平栈中(Embed in HStack)
  • 在位置控件的后面加一个公园状态的Text视图,并把占位文字改为California,字体设置为子标题样式
  • 为了水平布局使用整个屏幕宽度,在位置控件和公园状态控件中间添加一个Spacer控件,用来填充两个控件中间的空白部分,并把两个控件分别顶向屏幕的两侧。Spacer是一个可以伸缩的空白控件,他负责占用其它控件布局完成后剩下的所有空间
  • 使用padding()修改器给地标信息内容视图整体加内边距
struct ContentView: View {
    var body: some View {
        VStack(alignment: HorizontalAlignment.leading) {
            Text("Turtle Rock")
                .font(.title)
            HStack {
                Text("Joshua Tree Nation Park")
                    .font(.subheadline)
                Spacer()
                Text("California")
            }
        }
        .padding()
    }
}

创建自定义图像视图(Image)

有了地标名称、地标位置及状态视图,下一步再添加一个地标图片视图。这个图片视图将自定义遮罩(mask)、边框(border)和阴影(shadow)

  • 新建SwiftUI文件CircleImage
  • 用Image替换Text,并使用turtlerock图片初始化Image视图
  • 添加clipShape(Circle())修改器到Image,给图片添加圆形剪切效果。Circle是一个形状,它可以被用作遮罩、也可以是圆圈,还可以是圆形填充视图。
  • 创建另一个灰色的圆圈并把它作为一个浮层添加到图片上,相当于给图片加了一个灰色边框
  • 给视图添加半径为10的阴影
  • 把圆形边框的颜色改成白色,就完成了自定义图片视图的创建
struct CircleImage: View {
    var body: some View {
        Image("turtlerock")
            .clipShape(Circle())
            .overlay(Circle().stroke(Color.white, lineWidth: 4))
            .shadow(radius: 10)
    }
}

UIKit视图与SwiftUI视图混合使用

要创建一个地图视图,可以使用MapKit中的MKMapView视图类来渲染地图。要在SwiftUI中使用UIView及其子类,需要把这些UIView包裹在一个遵循UIViewRepresentable协议的SwiftUI视图中,SwiftUI中也包含适配WatchKit和AppKit的类似的协议。

  • 选择文件->新建->文件,选择iOS平台,选择SwiftUI View模板,并点击下一步(Next),命名文件为MapView.swift,并点击创建(Create)
  • 代码中导入MapKit引用,声明MapView遵循UIViewRepresentable协议。UIViewRepresentable协议要求实现两个方法用makeUIView(context:)和updateUIView(_:context:),第一个方法用来创建MKMapView,第二个方法用来配置视图响应状态变化
  • UIViewRepresentable协议需要指定关联类型UIViewType为MKMapView
  • 替换body,用makeUIView(context:)方法来代替,创建并返回一个空的MKMapView
  • 创建方法updateUIView(_:context:),在方法内部设置地图视图的坐标为Turle Rock的中心。在静态模式下预览时,只会渲染swiftUI视图的部分,因为MKMapView是UIView的子类,所以需要切换到实时预览模式下才能看到地图被完全渲染出来
  • 点击Live Preview(实时预览)按钮,可能需要点击Try Again和Resume按钮来激活预览模式的切换。切换到实时预览模式下不久就可以看到指定地标所在的地图位置了
struct MapView: UIViewRepresentable {
    typealias UIViewType = MKMapView
    func makeUIView(context: Context) -> MKMapView {
        return MKMapView(frame: .zero)
    }
    func updateUIView(_ uiView: 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)
        uiView.setRegion(region, animated: true)
    }
}

组合地标详情页

前面创建了个地标详情页所需要的各种子视图元素:名称、地点、圆形图片以及位置地图,现在可以把这些视图元素组合在一起形成地标详情页的整个视图

  • 在项目工程浏览器中选择ContentView.swift文件
  • body属性中嵌入一个VStack视图,它内部包含另一个VStack视图,内部的VStack视图又包含三个Text视图
  • 在外层VStack的顶部添加自定义的地图视图MapView,并使用frame(width:height:)设置视图大小。当只指定高度时,宽度会自动计算为父视图的宽度,在这里就是屏幕宽度
  • 点击Live Preview按钮进入实时预览模式,查看地图渲染情况。在实时预览模式下可以编辑视图,最新的改动也可以实时的刷新出来。
  • 在MapView后面再添加一个CircleImage视图
  • 为了让图片视图叠放在地图视图的上面,可以设置图片视图的垂直偏移量为-130,图片视图的底部内边距也为-130,这个效果就是把图片垂直上移了130,同时和下面的文字区域留出了130的空白分隔区
  • 在外层VStack内部的最下面加上Spacer,可以让上面的视图内容顶到屏幕的上边
  • 为了让地图的视图内容显示在状态栏的下方,可以给MapView添加edgesIgnoringSafeArea(.top)修改器,这可以让它在布局时忽略顶部的安全区域边距
struct ContentView: View {
    var body: some View {
        VStack {
            MapView().frame( height: 300)
                .edgesIgnoringSafeArea(.top)
            CircleImage().offset(y: -130)
                .padding(.bottom, -130)
            VStack(alignment: HorizontalAlignment.leading) {
                Text("Turtle Rock")
                    .font(.title)
                HStack {
                    Text("Joshua Tree Nation Park")
                        .font(.subheadline)
                    Spacer()
                    Text("California")
                }
            }
            .padding()
            Spacer()
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358

推荐阅读更多精彩内容