如何更改SwiftUI警报的颜色方案?

huangapple go评论62阅读模式
英文:

How to change SwiftUI alert color scheme?

问题

我已经实现了一个可以改变应用程序颜色方案的功能。一切都运行正常,除了带有TextField.alert()的颜色方案。

如果是白天并且颜色方案更改为.dark.alert()的颜色方案仍然是.light,包括TextField

这意味着当您在TextField中键入时,前景颜色是白色,因为在暗模式下,文本颜色会变为白色,您实际上看不到您在键入什么。

类似地,如果系统的颜色方案是.dark,而应用程序的颜色方案是白色,那么.alert会处于.dark模式,文本是黑色,因为应用程序中的文本是黑色。

TextFieldVStack应用.background()foregroundColor()没有任何效果。

是否有一种方法可以控制.alert()的颜色方案?或者我是否需要寻找.alert()的替代方案?

以下是一些代码以复现这种行为。谢谢!

import SwiftUI

struct ContentView: View {
    @State private var showAlert = false
    @State private var addSomething: String = ""
    @State private var isSystemMode = false
    @State private var isDarkMode = false

    var body: some View {
        VStack {
            VStack {
                Toggle("Automatic (iOS Settings)", isOn: $isSystemMode)
                if !isSystemMode {
                    Toggle("Dark Mode", isOn: $isDarkMode)
                }
            }
            Button{
                self.showAlert = true
            } label: {
                Text("Add something")
                    .frame(maxWidth: .infinity)
            }
            .alert("Add something", isPresented: $showAlert, actions: {
                TextField("Something", text: $addSomething)
                Button("Done") {
                    // Some action
                }
                Button("Cancel", role: .cancel, action: {})
            }, message: {
                Text("Type in something")
            })
        }
        .padding()
        .preferredColorScheme(isSystemMode ? .none : isDarkMode ? .dark : .light)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
英文:

I have implemented a functionality that changes the color scheme of the app. Everything works fine except the color scheme for the .alert() that has a TextField in it.

If is daylight and color scheme is changed to .dark, the .alert() color scheme is still .light includind the TextField.

That means that when you type something in the TextField, the foreground color is white, because the text color in dark mode changes to white, and you can't really see what you are typing.

Similar, if the system's color scheme is .dark and the app's color scheme is white, the .alert is in .dark mode and the text is black, because the text in the app is black.

Applying .background() or foregroundColor() to TextField or VStack doesn't have any effect.

Is there a way to control the color scheme for .alert()? Or do I have to look for an .alert() alternative?

Here is some code to reproduce the bahaviour. Thanks!

import SwiftUI

struct ContentView: View {
    @State private var showAlert = false
    @State private var addSomething: String = ""
    @State private var isSystemMode = false
    @State private var isDarkMode = false

    var body: some View {
        VStack {
            VStack {
                Toggle("Automatic (iOS Settings)", isOn: $isSystemMode)
                if !isSystemMode {
                    Toggle("Dark Mode", isOn: $isDarkMode)
                }
            }
            Button{
                self.showAlert = true
            } label: {
                Text("Add something")
                    .frame(maxWidth: .infinity)
            }
            .alert("Add something", isPresented: $showAlert, actions: {
                TextField("Something", text: $addSomething)
                Button("Done") {
                    // Some action
                }
                Button("Cancel", role: .cancel, action: {})
            }, message: {
                Text("Type in something")
            })
        }
        .padding()
        .preferredColorScheme(isSystemMode ? .none : isDarkMode ? .dark : .light)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

答案1

得分: 2

我认为要使这个工作起来的唯一方法是创建自定义提醒。以下是一个自定义提醒的示例,但你可能需要根据你的需求进行修改:

struct CustomAlertView<Content: View>: View {

    @Environment(\.colorScheme) var colorScheme

    let title: String
    let description: String

    var cancelAction: (() -> Void)?
    var cancelActionTitle: String?

    var primaryAction: (() -> Void)?
    var primaryActionTitle: String?

    var customContent: Content?

    init(title: String,
         description: String,
         cancelAction: (() -> Void)? = nil,
         cancelActionTitle: String? = nil,
         primaryAction: (() -> Void)? = nil,
         primaryActionTitle: String? = nil,
         customContent: Content? = EmptyView()) {
        self.title = title
        self.description = description
        self.cancelAction = cancelAction
        self.cancelActionTitle = cancelActionTitle
        self.primaryAction = primaryAction
        self.primaryActionTitle = primaryActionTitle
        self.customContent = customContent
    }

    var body: some View {
        // ...
    }
}

用法:

struct ContentView: View {
    @State private var showAlert = false

    var body: some View {
        ZStack {
            Button("Show alert") {
                withAnimation {
                    showAlert.toggle()
                }
            }
            if showAlert {
                CustomAlertView(
                    title: "Alert title",
                    description: "Description here",
                    cancelAction: {
                        // 取消操作在这里
                        withAnimation {
                            showAlert.toggle()
                        }
                    },
                    cancelActionTitle: "Cancel",
                    primaryAction: {
                      // 主要操作在这里
                        withAnimation {
                            showAlert.toggle()
                        }
                    },
                    primaryActionTitle: "Action",
                    customContent:
                        Text("Custom content here")
                        .padding([.trailing, .leading, .bottom])
                )
            }
        }
    }
}

如果你想包含一个TextField,只需添加:

customContent:
    TextField("Text here", text: $text)
    .textFieldStyle(.roundedBorder)
    .padding([.trailing, .leading, .bottom])
英文:

I think the only way to truly make this work is by making your own custom alert. Here is an example of a custom alert, but you might have to modify it according to your needs:

struct CustomAlertView&lt;Content: View&gt;: View {

    @Environment(\.colorScheme) var colorScheme

    let title: String
    let description: String

    var cancelAction: (() -&gt; Void)?
    var cancelActionTitle: String?

    var primaryAction: (() -&gt; Void)?
    var primaryActionTitle: String?

    var customContent: Content?

    init(title: String,
         description: String,
         cancelAction: (() -&gt; Void)? = nil,
         cancelActionTitle: String? = nil,
         primaryAction: (() -&gt; Void)? = nil,
         primaryActionTitle: String? = nil,
         customContent: Content? = EmptyView()) {
        self.title = title
        self.description = description
        self.cancelAction = cancelAction
        self.cancelActionTitle = cancelActionTitle
        self.primaryAction = primaryAction
        self.primaryActionTitle = primaryActionTitle
        self.customContent = customContent
    }

    var body: some View {
        HStack {
            VStack(spacing: 0) {
                Text(title)
                    .font(.system(size: 16, weight: .semibold, design: .default))
                    .padding(.top)
                    .padding(.bottom, 8)

                Text(description)
                    .font(.system(size: 12, weight: .light, design: .default))
                    .multilineTextAlignment(.center)
                    .padding([.bottom, .trailing, .leading])

                customContent

                Divider()

                HStack {
                    if let cancelAction, let cancelActionTitle {
                        Button { cancelAction() } label: {
                            Text(cancelActionTitle)
                                .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
                        }
                    }

                    if cancelActionTitle != nil &amp;&amp; primaryActionTitle != nil {
                        Divider()
                    }

                    if let primaryAction, let primaryActionTitle {
                        Button { primaryAction() } label: {
                            Text(&quot;**\(primaryActionTitle)**&quot;)
                                .frame(minWidth: 0, maxWidth: .infinity, alignment: .center)
                        }
                    }
                }.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 50, alignment: .center)
            }
            .frame(minWidth: 0, maxWidth: 400, alignment: .center)
            .background(.ultraThickMaterial)
            .cornerRadius(10)
            .padding([.trailing, .leading], 50)
        }
        .zIndex(1)
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        .background(
            colorScheme == .dark
            ? Color(red: 0, green: 0, blue: 0, opacity: 0.4)
            : Color(red: 1, green: 1, blue: 1, opacity: 0.4)
        )
    }
}

Usage:

struct ContentView: View {
    @State private var showAlert = false

    var body: some View {
        ZStack {
            Button(&quot;Show alert&quot;) {
                withAnimation {
                    showAlert.toggle()
                }
            }
            if showAlert {
                CustomAlertView(
                    title: &quot;Alert title&quot;,
                    description: &quot;Description here&quot;,
                    cancelAction: {
                        // Cancel action here
                        withAnimation {
                            showAlert.toggle()
                        }
                    },
                    cancelActionTitle: &quot;Cancel&quot;,
                    primaryAction: {
                      // Primary action here
                        withAnimation {
                            showAlert.toggle()
                        }
                    },
                    primaryActionTitle: &quot;Action&quot;,
                    customContent:
                        Text(&quot;Custom content here&quot;)
                        .padding([.trailing, .leading, .bottom])
                )
            }
        }
    }
}

If you want to include a TextField simply do:

customContent:
    TextField(&quot;Text here&quot;, text: $text)
    .textFieldStyle(.roundedBorder)
    .padding([.trailing, .leading, .bottom])

如何更改SwiftUI警报的颜色方案?

huangapple
  • 本文由 发表于 2023年4月6日 20:27:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75949514.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定