SwiftUI:自定义含Text的视图如何支持全部Text修饰符?
问题原因
在iOS 15里,.font是所有View都支持的环境类修饰符,会自动传递给子视图,所以能生效;但.tracking、.fontWeight这类是Text专属的实例方法,你的ScrollText是自定义View,本身没有这些方法,iOS 15不会自动把这些修饰符转发给内部的Text组件,所以只有.font能用。
解决方案
方案一:通过自定义环境变量传递修饰符(支持扩展更多修饰符)
这种方式通过环境变量把修饰符参数传递给内部Text,扩展性更强,后续要加其他Text修饰符也可以用类似逻辑:
- 定义对应环境键,用来传递修饰符参数:
// 传递tracking参数的环境键 struct TrackingEnvironmentKey: EnvironmentKey { static let defaultValue: CGFloat? = nil } extension EnvironmentValues { var textTracking: CGFloat? { get { self[TrackingEnvironmentKey.self] } set { self[TrackingEnvironmentKey.self] = newValue } } } // 传递fontWeight参数的环境键 struct FontWeightEnvironmentKey: EnvironmentKey { static let defaultValue: Font.Weight? = nil } extension EnvironmentValues { var textFontWeight: Font.Weight? { get { self[FontWeightEnvironmentKey.self] } set { self[FontWeightEnvironmentKey.self] = newValue } } }
- 给View添加扩展,实现对应的修饰符方法,把参数存入环境变量:
extension View { func tracking(_ amount: CGFloat) -> some View { self.environment(\.textTracking, amount) } func fontWeight(_ weight: Font.Weight?) -> some View { self.environment(\.textFontWeight, weight) } }
- 修改ScrollText,读取环境变量并应用到内部的Text上:
struct ScrollText: View { let text: String @Environment(\.font) private var font @Environment(\.textTracking) private var tracking @Environment(\.textFontWeight) private var fontWeight var body: some View { Text("\(text) the logic is like that") .font(font) .applyIf(tracking != nil) { $0.tracking(tracking!) } .fontWeight(fontWeight) } } // 辅助工具:根据条件决定是否应用修饰符 extension View { func applyIf<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View { condition ? transform(self) : self } }
方案二:让ScrollText自身实现Text的修饰符方法(调用方式和原生Text完全一致)
直接在ScrollText里添加对应属性和修饰符方法,把参数传递给内部Text,调用起来和原生Text一模一样:
struct ScrollText: View { let text: String private var font: Font? = nil private var tracking: CGFloat? = nil private var fontWeight: Font.Weight? = nil var body: some View { Text("\(text) the logic is like that") .font(font) .applyIf(tracking != nil) { $0.tracking(tracking!) } .fontWeight(fontWeight) } // 实现font修饰符 func font(_ font: Font?) -> ScrollText { var copy = self copy.font = font return copy } // 实现tracking修饰符 func tracking(_ amount: CGFloat) -> ScrollText { var copy = self copy.tracking = amount return copy } // 实现fontWeight修饰符 func fontWeight(_ weight: Font.Weight?) -> ScrollText { var copy = self copy.fontWeight = weight return copy } } // 辅助工具:根据条件决定是否应用修饰符 extension View { func applyIf<Content: View>(_ condition: Bool, transform: (Self) -> Content) -> some View { condition ? transform(self) : self } }
两种方案都能让你在iOS 15里像使用原生Text一样,给ScrollText链式调用所有需要的修饰符。
内容的提问来源于stack exchange,提问作者Perry Wang
相关产品推荐
相关产品推荐

