我正在嘗試制作可重用的自定義視圖,以后可以對其進行自定義。理想情況下,我可以定義默認的修飾符,如顏色、字體等,這些修飾符在沒有任何自定義的情況下視圖將具有,但允許它們很容易被稍后使用的其他修飾符覆寫。
例如,如果我有自定義視圖:
struct MyCustomTextField: View {
@Binding var text: String
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(.gray)
.font(.system(.title))
}
}
}
視圖將具有默認的灰色前景色,并且 TextField 將具有標題字體。但是現在如果我想重用這個視圖并為我的特定用例定制它,我可能想像這樣覆寫這些修飾符:
struct ContentView: View {
@State var text = "hello"
var body: some View {
MyCustomTextField(text: $text)
.foregroundColor(.blue)
.font(.system(.body))
}
}
但是這些外部修飾符無效,因為內部修飾符具有先例。
制作自定義視圖的最佳方法是什么,以便我可以為其內容定義默認修飾符,但以后仍然可以覆寫這些默認值?
謝謝
uj5u.com熱心網友回復:
我們應該永遠記住 SwiftUI 視圖是值型別,因此您不能像在 UIKit 上那樣在初始化后更改它們。一種可能的方法是在初始化時注入它。但是,如果您想在初始化后使其可調整(例如,在按下其他按鈕時更改顏色),請使用系結機制:
將 a 添加@Binding到您的 MyCustomTextField,并在 foregroundColor 修飾符處使用其值。
struct MyCustomTextField: View {
@Binding var text: String
@Binding var foregroundColor: Color
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(foregroundColor)
.font(.system(.title))
}
}
}
然后在客戶端視圖中,您可以執行以下操作:
struct MyView: View {
@State var myText: String = ""
@State var hasSpecialColor: Bool = false
var foregroundColor: Binding<Color> {
return Binding<Color>(get: {
return hasSpecialColor ? Color.red : Color.black
}, set: { newValue in
hasSpecialColor = newValue == Color.red
})
}
var body: some View {
VStack {
Text("Some Header Text")
MyCustomTextField(text: $myText, foregroundColor: foregroundColor)
Button("click to toggle color") {
hasSpecialColor.toggle()
}
}
}
}
現在,每次單擊按鈕時,它都會切換 hasSpecialColor(即@State),因此視圖將呈現,并且@Binding前景顏色的值將相應更改。
uj5u.com熱心網友回復:
您可以Font通過環境中最近的font修飾符找到集合,因此您可以閱讀它并提供如下默認值:
struct MyCustomTextField: View {
@Binding var text: String
@Environment(\.font)
var envFont: Font?
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(.gray)
.font(envFont ?? .system(.title))
}
}
}
不幸的是,foregroundColor修改器不會將其設定存盤在(公共)環境屬性中,因此您必須走不同的路線。一種方法是直接在自定義視圖上提供修飾符,如下所示:
struct MyCustomTextField: View {
@Binding var text: String
var _myColor: Color = .gray
@Environment(\.font)
var envFont: Font?
func myColor(_ color: Color) -> Self {
var copy = self
copy._myColor = color
return copy
}
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(_myColor)
.font(envFont ?? .system(.title))
}
}
}
然后,您可以像這樣myColor直接使用修飾符MyCustomTextField:
PlaygroundPage.current.setLiveView(
MyCustomTextField(text: .constant("hello"))
.myColor(.red)
.padding()
.font(.body)
)
但是您不能在任何封閉視圖上或在任何非MyCustomTextField特定修飾符之后使用它。例如,這將不起作用:
PlaygroundPage.current.setLiveView(
MyCustomTextField(text: .constant("hello"))
.padding()
.myColor(.red) // Error: Value of type 'some View' has no member 'myColor'
.font(.body)
)
如果你想讓它作業,那么你需要將自定義顏色存盤在環境中,如下所示:
struct MyColor: EnvironmentKey {
static var defaultValue: Color? { nil }
}
extension EnvironmentValues {
var myColor: Color? {
get { self[MyColor.self] }
set { self[MyColor.self] = newValue }
}
}
extension View {
func myColor(_ color: Color?) -> some View {
return self.environment(\.myColor, color)
}
}
struct MyCustomTextField: View {
@Binding var text: String
@Environment(\.myColor)
var envColor: Color?
@Environment(\.font)
var envFont: Font?
var body: some View {
HStack {
Image(systemName: "envelope").foregroundColor(.gray)
TextField("", text: $text)
.foregroundColor(envColor ?? .gray)
.font(envFont ?? .system(.title))
}
}
}
然后你可以myColor在任何視圖上使用修飾符,它將應用于所有封閉的子視圖:
PlaygroundPage.current.setLiveView(
MyCustomTextField(text: .constant("hello"))
.padding()
.myColor(.red)
.font(.body)
)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/413435.html
標籤:
