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()
        }
    }
}

© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...