SwiftUI中ViewModifiers的使用
在
SwiftUI中,在View上大多数调用的方法都称为Modifier,一种是为原地Modifier,另外一种为封装类Modifier。原地Modifier是返回同样类型的View,封装类Modifier则可以返回不同类型的View,在开发中我们经常需要自定义ViewModifier来对View进行特定的变换操作。
Text("Hello, World!")
.font(.title)
.foregroundColor(.white)
.padding()
.background(Color.orange)
ViewModifier-1.png
原地Modifier
上面的font和foregroundColor则为原地Modifier,对Text进行字体大小和颜色的设置后返回的依然是一个Text,原地 modifier一般来说对顺序不敏感,对布局也不关心,它们更像是针对对象View本身的属性的修改。
封装类Modifier
上面的padding和background则为封装类Modifier,对Text进行内边距和背景色的设置后返回的是一个封装后的Text。padding和background是定义在View extension中的,对顺序十分敏感,所造成的布局影响是严格按照顺序执行的。
Text("Hello, World!")
.font(.title)
.foregroundColor(.white)
.background(Color.orange)
.padding()
.background(Color.blue)
ViewModifier-2.png
注意到设置
padding前的橘色背景并没有包覆内边距,而蓝色背景则包覆了内边距,蓝色背景其实是覆盖整个矩形的。
自定义Modifier
- 定义一个
Struct继承自ViewBuilder这个协议 - 实现
func body(content:Content) -> some View {}这个方法,此方法接受一个View,返回一个View,方法的实现则是上面所说的变换(当然也可以不变换)。
struct Title: ViewModifier {
func body(content: Content) -> some View {
content
.font(.largeTitle)
.foregroundColor(.white)
.padding()
.background(Color.blue)
.clipShape(RoundedRectangle(cornerRadius: 10))
}
}
这里我们定义了一个名为Title的Modifier,然后对输入的View进行了字体大小,前景色(字体颜色),内边距,背景色和圆角等一系列属性设置,当然这些设置也使用了苹果封装好的ViewModifier。
自定义Modifier的使用
- 方式1
Text("Hello, World!")
.modifier(Title())
- 方式2
ModifiedContent(content: Text("Hello, world!"), modifier: Title())
ViewModifier.png
利用自定义Modifier创建一个新的View
struct Watermark: ViewModifier {
var text: String
func body(content: Content) -> some View {
ZStack(alignment: .bottomTrailing) {
content
Text(text)
.font(.caption)
.foregroundColor(.white)
.padding(5)
.background(Color.black)
}
}
}
extension View {
func watermarked(with text: String) -> some View {
self.modifier(Watermark(text: text))
}
}
这里我们定义了一个名为Watermark的Modifier,将传入的View和一个预定义属性的Text用ZStack包起来作为新的View返回,这就是上文所述的不同类型View的变换操作,在开发中最为常见。
Color.blue
.frame(width: 300, height: 200)
.watermarked(with: "Hacking with Swift")
ViewModifier-4.png
总结
ViewModifiers允许我们在视图中封装和重用任何逻辑,利用自定义的Modifier能全局改变SwiftUI的控件样式,非常好用!且自定义非常简单,只需要满足ViewBuild协议并实现body方法即可。