Transforming View
- 使用offset设置视图的偏移位置
- 在View的周围填充颜色
- 重复使用修饰符创建阴影效果
- 给View绘制边框
- 给形状View绘制边框
- 创建动态虚线边框(跑马灯)
- 如何在View周围绘制阴影
- 裁剪View,使部分可见
- View的旋转
- View的3D旋转
- View的放大和缩小
概述
文章主要分享SwiftUI Modifier的学习过程,将使用案例的方式进行说明。内容浅显易懂,Transforming View展示部分调试结果,不过测试代码是齐全的。如果想要运行结果,可以移步Github下载code -> github案例链接
1、使用offset设置视图的偏移位置
所有视图在层次结构中都有一个默认位置,但是Offset()
修饰符可以相对于该默认位置移动它们。在ZStack中使用时,可以控制视图应该如何重叠。
使用offset()将导致视图相对于其默认位置移动,但不会影响视图的位置或偏移之后的任何其他修饰符。这意味着可以要仔细考虑如何使用这个特性,尤其是要确保视图不会重叠。
1.1、视图重叠问题
例如,在这个VStack中,使用Offset()将第二个View向下移动15个点,结果是与第三个View重叠了。
struct FFViewOffset: View {
var body: some View {
Text("Home")
Text("Options")
.offset(y: 15)
Text("Help")
}
}
1.2、padding()一起使用解决重叠问题
将padding()
与offset()一起使用会得到真正预测的结果,因为这会移动一个视图。同时还会自动调整旁边的视图。
struct FFViewOffset: View {
var body: some View {
Text("Home")
Text("Options")
.offset(y: 15)
.padding(.bottom, 15)
Text("Help")
}
}
1.3、.offset之前与之后的不同
任何放在offset()之后的修饰符都不会收到位置变化的影响,这可能会导致意想不到的结果。我在偏移量之前和之后都使用了background()
struct FFViewOffset: View {
var body: some View {
HStack {
Text("Before")
.background(.red)
.offset(y: 15)
Text("After")
.offset(y: 15)
.background(.green)
}
}
}
1.4、在ZStack中使用
当与ZStack结合时,偏移量让我们将一个视图放置在另一个视图中,用于控制ZStack的对齐
struct FFViewOffset: View {
var body: some View {
ZStack(alignment: .bottomTrailing) {
Image(.filletSteak)
Text("Photo credit: Meta BBLv")
.padding(4)
.background(.black)
.foregroundStyle(.white)
.offset(x: -15 ,y: -5)
}
}
}
调试结果
2、在View的周围填充颜色
padding()修饰符可以在视图周围添加一些间距,background()修饰符可以设置背景颜色
2.1、在padding之前设置背景色
struct FFViewPaddingAroundColor: View {
var body: some View {
Text("metaBBLv with Swift")
.background(.red)
.foregroundStyle(.white)
.padding()
}
}
2.2、在padding之后设置背景色
struct FFViewPaddingAroundColor: View {
var body: some View {
Text("metaBBLv with Swift")
.padding()
.background(.red)
.foregroundStyle(.white)
}
}
这两段code可能看起来比较相似,但是产生不同的结果,因为使用修饰符的顺序很重要。在第二个例子中,视图被填充,然后着色,这意味着填充的范围也被着色。相比之下,第一个例子就是先着色再填充。
调试结果
3、重复使用修饰符创建阴影效果
添加到视图中的每个修饰符都会调整之前的任何修饰符,并可以多次重复修饰符
。
struct FFAdvancedEffects: View {
var body: some View {
Text("Hello, metaBBLv")
.font(.largeTitle)
.foregroundStyle(.white)
.padding()
.background(.red)
.padding()
.background(.orange)
.padding()
.background(.yellow)
//这对于创建阴影,可以根据需求来重复使用修饰符。
}
}
调试结果
4、给View绘制边框
SwiftUI为有一个专门的border()
修饰符来绘制视图周围的边框。它有一些变化取决于你是否想要指定宽度和圆角半径。
struct FFViewBorder: View {
var body: some View {
Text("metaBBlv with Swift")
.border(.green)
Divider()
//添加一些padding来调整边框
Text("metaBBlv with Swift")
.padding()
.border(.green)
Divider()
//设置Border的宽度
Text("metaBBlv with Swift")
.padding()
.border(.red, width: 4)
Divider()
//添加圆角边框,使用overlay()修饰符。
Text("metaBBlv with Swift")
.padding()
.overlay {
RoundedRectangle(cornerRadius: 16)
.stroke(.blue, lineWidth: 4)
}
}
}
设置边框使用的修饰符:
- 对形状类型使用stroke()或strokeBorder()
- 对其他视图类型使用border()
调试结果
5、给形状View绘制边框
SwiftUI有stroke()
和strokeBorder()
修饰符,用于在形状周围绘制border,略有不同:
- strokeBorder()修饰符将视图插入边框高度的一半,然后应用边框,这意味着整个边框都在视图内绘制。
- stroke()修饰符以视图的边缘为中心绘制border,这意味着一半的border在视图内部,一半在外部。
重要提示:这两个修饰符只适用于形状(Circle、Rectangle、Capsule等视图),不能对Text、Image等其他非形状视图使用。如果想在非形状视图周围绘制边框,使用border修饰符
5.1、strokeBorder
struct FFViewBorderInside: View {
var body: some View {
Circle()
.strokeBorder(Color.blue, lineWidth: 50)
.frame(width: 200, height: 200)
.padding()
}
}
因为使用了strokeBorder(),所以50宽度的边框全部在圆的内部
5.2、stroke
struct FFViewBorderInside: View {
var body: some View {
Circle()
.stroke(.green, lineWidth: 50)
.frame(width: 200, height: 200)
.padding()
}
}
调试结果
6、创建动态虚线边框(跑马灯)
SwiftUI的stokeBorder修饰符可以添加类似间断破折号(-)的类似效果。
struct FFBorderEffect: View {
@State private var phase = 0.0
var body: some View {
Spacer()
//使用[10]作为dash参数意味着SwiftUI将绘制我们的喵天的10个点,然后绘制10个点的空间,
//重复该模式,直到整个矩形被描边。它是一个数组,因为你可以提供多个值,例如[10,5],10表示秒变长度,5表示间隙。
Rectangle()
.strokeBorder(style: StrokeStyle(lineWidth: 4, dash: [10]))
//当添加破折号时(-),它决定了破折号和间隙应该放在哪里。如果我们将该阶段存储在状态属性中,那么就可以随着时间的推移将该值动画化,创建所谓的动态虚线描边。
Spacer()
Rectangle()
.strokeBorder(style: StrokeStyle(lineWidth: 4,dash: [10], dashPhase: phase))
.frame(width: 200, height: 200)
.onAppear {
withAnimation(.linear.repeatForever(autoreverses: false), {
phase -= 20
})
}
Spacer()
}
}
调试结果
图二是动态效果,需要在demo里自己尝试,由于我偷懒了,并没有做Gif图。
7、如何在View周围绘制阴影
SwiftUI给了我们两种创建阴影的方式:
- 直接阴影附加到形状样式上
- 使用shadow修饰符绘制阴影。
7.1、常规样式
struct FFViewShadow: View {
var body: some View {
Circle()
.fill(.red.shadow(.drop(color: .black, radius: 10)))
.padding()
}
}
7.2、内部阴影
struct FFViewShadow: View {
var body: some View {
Circle()
.fill(.green.shadow(.inner(color: .black ,radius: 10)))
.padding()
}
}
7.3、shadow()
可以控制阴影的颜色、半径、和位置,还可以通过调整修饰符的顺序来控制视图的那些部分为阴影。如果希望将阴影附加到其他类型视图上,则应该使用shadow()
修饰符 ,在其基本形式中,可以通过指定模糊半径来添加阴影。
struct FFViewShadow: View {
var body: some View {
Text("metaBBLv with Swift")
.foregroundStyle(.black)
.padding()
.shadow(radius: 5)
.border(.red, width: 4)
.background(.white)
}
}
7.4、.shadow(color: .red, radius: 5)
添加了非常轻微的阴影,在文本中心5点模糊。还可以指定想要的颜色以及与原始视图X和Y的偏移量。例如,创建一个带有5点模糊的强烈红色阴影,以文本为中心。
struct FFViewShadow: View {
var body: some View {
Text("metaBBLv with Swift")
.padding()
.shadow(color: .red, radius: 5)
.border(.red, width: 4)
}
}
7.5、.shadow(color: .red, radius: 5, x: 20, y: 20)
如果想为阴影指定偏移量,添加x、y
struct FFViewShadow: View {
var body: some View {
Text("metaBBLv with Swift")
.padding()
.shadow(color: .red, radius: 5, x: 20, y: 20)
.border(.red, width: 4)
}
}
7.6、.shadow(color: .red, radius: 5, x: 20, y: 20)
SwiftUI按照你列出的顺序使用修饰符,所以想让你的阴影也应用到边框上,只要把边框修饰符放在阴影之前。
struct FFViewShadow: View {
var body: some View {
Text("metaBBLv with Swift")
.padding()
.border(.red, width: 4)
.shadow(color: .red, radius: 5, x: 20, y: 20)
}
}
如果发现你阴影效果不够强,添加另一个shadow()修饰符,可以把它们叠加起来创建更复杂的阴影效果。
调试结果
8、裁剪View,使部分可见
SwiftUI可以裁剪任何视图来控制他的形状,这都是通过使用clipShape()
修饰符实现的。Circle裁剪形状将始终从视图中生成圆,即使他们的高度和宽度不相等。它只会裁剪较大的值以匹配较小的值。
struct FFViewClip: View {
var body: some View {
Button {
print("Button was pressed!")
} label: {
Image(systemName: "bolt.fill")
.foregroundStyle(.white)
.padding()
.background(.green)
.clipShape(Circle())
}
//除了Circle,还有Capsule,它可以将视图裁剪成菱形的圆角。类似胶囊形状
Button {
print("Pressed!")
} label: {
Image(systemName: "bolt.fill")
.foregroundStyle(.white)
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.background(.green)
.clipShape(Capsule())
}
//我在哪里添加了一些更精确的padding来获得更准确的形状。
}
}
调试结果
9、View的旋转
SwiftUI的RotationEffect()
修饰符让我们可以自由旋转视图,使用角度或弧度。
struct FFViewRotate: View {
@State private var rotation = 50.0
@State private var rotation1 = 20.0
var body: some View {
//将Text旋转-90度
Text("Hello, World!")
.rotationEffect(.degrees(-90))
Divider()
.padding(.top, 50)
//使用.radians设置弧度。
Text("Hello, World!")
.rotationEffect(.radians(.pi))
//使用Silder控制旋转
Divider()
VStack {
Slider(value: $rotation, in: 0...360)
.padding(.bottom, 50)
Text("Hello, World!")
.rotationEffect(.degrees(rotation))
}
.padding()
//默认情况下,视图围绕其中心旋转,但如果你想固定从特定的点旋转,
//可以为此添加一个额外的参数。例如,围绕左上角旋转。
Divider()
VStack {
Slider(value: $rotation1, in: 0...360)
.padding(.bottom, 50)
Text("Hello, World!")
.rotationEffect(.degrees(rotation1), anchor: .topLeading)
}
.padding()
}
}
调试结果
可以根据Slider动态调整旋转角度,自行demo探索
10、View的3D旋转
SwiftUI的rotation3DEffect()
修饰符可以在3D空间中旋转视图,几乎不需要太多的代码就可以创造非常好的效果。它接受两个参数:要旋转的角度(以弧度或度为单位),以及包含要绕其旋转的X、Y和Z轴的元祖。
struct FFViewRotate3D: View {
var body: some View {
//将Text围绕X轴旋转45度
Text("METABBLV SWIFTUI")
.font(.largeTitle)
.foregroundStyle(.green)
.rotation3DEffect(.degrees(45), axis: (x: 1, y: 0, z:0))
}
}
调试结果
11、View的放大和缩小
SwiftUI的scaleEffect()修饰符让我们可以自由的放大或缩小
视图。
struct FFViewScale: View {
var body: some View {
//放大
Text("Hello, World!")
.scaleEffect(3)
.frame(width: 300, height: 100)
Spacer()
//在X轴与Y轴之上做更改,可以压缩图像
Text("Hello, World!")
.scaleEffect(x: 1, y: 5)
.frame(width: 300, height: 100)
Spacer()
//指定一个锚点进行缩放。
Text("Hello, World!")
.scaleEffect(2, anchor: .bottomTrailing)
//获得一个两倍大小的文本视图,从右下角开始缩放。
Spacer()
//对照组
Text("Hello, World!")
Spacer()
}
}
缩放视图不会导致它以新的大小重新绘制,只会在不同方向上拉伸。这意味着小的文本看起来模糊,小的图像可能看起来像素化或模糊。