使用ViewModifier统一App的视觉效果
2年前 • 964次点击 • 来自 移动端
标签: SwiftUI
原文链接:
簡化大量 modifier 程式的 SwiftUI ViewModifier
在开发SwiftUI App的过程中,我们时常需要设置Text,Button的样式,在很多情况下都使用了统一的样式代码,例如:PoetView的文字使用白色(.foregroundColor(.white))、粗体(.font(.system(size: 30, weight: .bold)))、阴影效果.shadow(radius: 20),那么此时就可以使用ViewModifier提炼出这些样式,以后在其他页面即可使用这个样式,统一视觉效果的同时方便修改。
ViewModifier的功能特性类似 CSS中的Class 或者 Android中的Style 。
struct PoemView: View {
let poems = ["金樽清酒斗十千, 玉盘珍羞直万钱。", "停杯投箸不能食, 拔剑四顾心茫然。", "欲渡黄河冰塞川, 将登太行雪满山。", "闲来垂钓碧溪上, 忽复乘舟梦日边。", "行路难,行路难, 多歧路,今安在?", "长风破浪会有时, 直挂云帆济沧海。"]
var body: some View {
NavigationView {
ScrollView {
ForEach(poems, id: \.self) { poem in
Text(poem)
.modifier(PoemTextViewModifier(size: 20))
}
.navigationBarTitle("行路难")
}
}
}
}
struct PoemTextViewModifier: ViewModifier {
let size: CGFloat
func body(content: Content) -> some View {
content
.foregroundColor(.black)
.font(.system(size: size, weight: .bold))
.foregroundColor(.white)
.shadow(radius: 20)
}
}
改进
直接使用 .modifier(PoemTextViewModifier(size: 20)) 也没什么问题,更简洁的写法是将它处理成extension:
写法一:
extension View {
func PoemTextStyle(size: CGFloat) -> some View {
modifier(PoemTextViewModifier(size: size))
}
}
写法二:
使用func modifier
extension View {
func PoemTextStyle(size: CGFloat) -> some View {
ModifiedContent(content: self, modifier: PoemTextViewModifier(size: size))
}
}
以上2种写法,如下调用:
Text(poem).PoemTextStyle(size: 20)
最后代码如下:
struct PoemView: View {
let poems = ["金樽清酒斗十千, 玉盘珍羞直万钱。", "停杯投箸不能食, 拔剑四顾心茫然。", "欲渡黄河冰塞川, 将登太行雪满山。", "闲来垂钓碧溪上, 忽复乘舟梦日边。", "行路难,行路难, 多歧路,今安在?", "长风破浪会有时, 直挂云帆济沧海。"]
var body: some View {
NavigationView {
ScrollView {
ForEach(poems, id: \.self) { poem in
Text(poem)
.PoemTextStyle(size: 20)
}
.navigationBarTitle("行路难")
}
}
}
}
extension View {
func PoemTextStyle(size: CGFloat) -> some View {
ModifiedContent(content: self, modifier: PoemTextViewModifier(size: size))
}
}
struct PoemTextViewModifier: ViewModifier {
let size: CGFloat
func body(content: Content) -> some View {
content
.foregroundColor(.black)
.font(.system(size: size, weight: .bold))
.foregroundColor(.white)
.shadow(radius: 20)
}
}