第七节 正向传值
在之前我们已经完成了跳转的部分,但是只是跳转到一个Text View,现在我们新建一个SwiftUI View:SceneryView.swift 文件,用来显示跳转后的页面
在新的页面,我们先创建好所需的视图,这里我们采用 ZStack 深浅的布局,使得图片和文字叠加
struct SceneryView: View {
var body: some View {
ZStack {
Image("埃及-金字塔-黄昏")
Text("埃及")
}
}
}
为了能够在这个页面接收上一个页面传进来的值,我们定义一个属性 “scenery”
这个时候在下面的 SceneryView_Previews 预览代码就会提示我们,我们定义了一个值,但是没有进行传值操作
我们点击“Fix”自动修复,填入我们之前定义的sceneries数组
struct SceneryView_Previews: PreviewProvider {
static var previews: some View {
SceneryView(scenery: sceneries[0])
}
}
我们可以发现,在每一个SwiftUI View下方都有一个Previews,它的作用就是让我们可以调试数据,然后预览效果。它只会在debug状态下有效,在运行后这部分的代码的不会有效的。
我们将代码修改一下如图所示,可以看到在Previews中可以测试我们需要显示的内容
然后回到第一个页面,将跳转的destination目标改为我们新建的SceneryView,并且参照刚才Presviews的代码,我们写下如下代码
这时候点击右边画布的,就可以发现我们已经实现了正向传值了。
最后我们完善一下SceneryView的布局设置
struct SceneryView: View {
let scenery: Scenery
var body: some View {
// 对齐方式:底部右对齐
ZStack(alignment: .bottomTrailing) {
Image(scenery.imageName)
// 让图片不超出父控件范围
.resizable()
// 自适应比例模式
.aspectRatio(contentMode: .fit)
// 设置最小、最大宽高
.frame(minWidth: 0, idealWidth: 0, maxWidth: .infinity, minHeight: 0, idealHeight: 0, maxHeight: .infinity, alignment: .center)
Text(scenery.location)
// 字体
.font(.largeTitle)
// 四周边距
.padding()
// 颜色
.foregroundColor(.secondary)
}
// 导航栏显示样式为inline
.navigationBarTitle(Text(scenery.name), displayMode: .inline)
}
}
这里是.infinity是指无穷大,结合.resizble和.fit的限制,图片就会在当前区域自动寻找到最合适的高度,这个应该比较好理解
根据截图可以看出Image和Text的区域
第八节 状态绑定和缩放动画
为了达到点击图片出现缩放的效果,我们需要给图片添加一个点击手势事件,并且需要用一个变量来记录点击的状态,这个我们就需要使用到状态绑定这个知识点。
关于@State的说明:加了@State注解的变量,视图通过监视和读取该变量来重新渲染UI。其状态是由SwiftUI来存储管理的,作为视图渲染的单一可信来源。
意思也很简单,就是一旦使用了@State修饰变量,一旦变量的值发生改变,SwiftUI就会自动刷新页面,不需要我们手动去刷新。
我们在View中定义一个用来记录缩放的变量zoomed,然后根据zoomed的状态来改变图片的显示模式,代码如下
struct SceneryView: View {
let scenery: Scenery
@State var zoomed = false
var body: some View {
// 对齐方式:底部右对齐
ZStack(alignment: .bottomTrailing) {
Image(scenery.imageName)
// 让图片不超出父控件范围
.resizable()
// 根据zoomed状态进行调整
.aspectRatio(contentMode: zoomed ? .fill : .fit)
// 设置最小、最大宽高
.frame(minWidth: 0, idealWidth: 0, maxWidth: .infinity, minHeight: 0, idealHeight: 0, maxHeight: .infinity, alignment: .center)
.onTapGesture {
// toggle相当于对值取反
zoomed.toggle()
}
Text(scenery.location)
// 字体
.font(.largeTitle)
// 四周边距
.padding()
// 颜色
.foregroundColor(.secondary)
}
// 导航栏显示样式为inline
.navigationBarTitle(Text(scenery.name), displayMode: .inline)
}
}
到这里我们就实现了图片点击缩放的效果,也是超级简单。得力于@State状态绑定的特性,我们可以很快捷的得到我们想看到的预览效果。
接下来我们再给缩放添加一个简单动画效果:withAnimation
.onTapGesture {
// toggle相当于对值取反
withAnimation {
zoomed.toggle()
}
}
完成了图片的处理,紧接着我们开始对Text View的动画进行处理
首先我们完成消失/显示的处理
if !zoomed {
Text(scenery.location)
.font(.largeTitle)
.foregroundColor(.secondary)
.padding()
}
这里就是表示当zoomed为false时,显示Text View,为true时隐藏Text View。
另外还有一个向右边移动的动画,这个时候我们需要使用到 transition
在SwiftUI中,transition决定了某个View如何插入到视图栈中,或者如何在视图栈中移除。transition自身并没有任何效果, 需要配合动画一起使用
if !zoomed {
Text(scenery.location)
.font(.largeTitle)
.foregroundColor(.secondary)
.padding()
// 向右边边距移动
.transition(.move(edge: .trailing))
}
到这里我们所有的代码都写完了,可以说总共不到一百行的代码,却实现了很多内容。不得不说SwiftUI是真的简洁好用,已经不想写OC的代码了,哈哈哈。