swift - 根据禁用与否更改SwiftUI中按钮的颜色

标签 swift swiftui

我有一个带有发送按钮的文本字段,该按钮是一个systemImage箭头。我希望图像的前景色根据textField是否为空而改变。 (即按钮为灰色,如果文本字段为空,则禁用该按钮。如果文本字段文本的计数> 1,则为蓝色)。

我有一个不完善的解决方法:


if chatMessageIsValid {
                Spacer()
                HStack {
                    TextField($chatMessage, placeholder: Text("Reply"))
                        .padding(.leading, 10)
                        .textFieldStyle(.roundedBorder)
                    Button(action: sendMessage) {
                        Image(systemName: "arrow.up.circle")
                            .foregroundColor(Color.blue)
                            .padding(.trailing, 10)
                        }.disabled(!chatMessageIsValid)
                }
            } else {
                Spacer()
                HStack {
                    TextField($chatMessage, placeholder: Text("Reply"))
                        .padding(.leading, 10)
                        .textFieldStyle(.roundedBorder)
                    Button(action: sendMessage) {
                        Image(systemName: "arrow.up.circle")
                            .foregroundColor(Color.gray)
                            .padding(.trailing, 10)
                        }.disabled(!chatMessageIsValid)
                }
            }

这几乎可以工作,并且如果文本的长度> 1,它的确会更改图像的颜色。但是,由于状态的变化,您在键入一个字符后将无法再编辑文本字段,因此您需要再次选择文本字段才能继续输入。是否有更好的方法使用.disabled修饰符来做到这一点?

最佳答案

我想你想要这个:

demo

您可以为按钮颜色添加一个计算属性,然后将该属性传递给按钮的foregroundColor修饰符。您还可以在padding周围使用单个HStack修饰符,而不是在其 subview 上使用单独的padding

struct ContentView : View {
    @State var chatMessage: String = ""

    var body: some View {
        HStack {
            TextField($chatMessage, placeholder: Text("Reply"))
                .textFieldStyle(.roundedBorder)
            Button(action: sendMessage) {
                Image(systemName: "arrow.up.circle")
                    .foregroundColor(buttonColor)
            }
                .disabled(!chatMessageIsValid)
        }
            .padding([.leading, .trailing], 10)
    }

    var chatMessageIsValid: Bool {
        return !chatMessage.isEmpty
    }

    var buttonColor: Color {
        return chatMessageIsValid ? .accentColor : .gray
    }

    func sendMessage() {
        chatMessage = ""
    }
}

但是,您完全不应该在这里使用foregroundColor修饰符。您应该使用accentColor修饰符。使用accentColor有两个好处:
  • 启用Image时,accentColor将自动使用环境的Button,而禁用Button时,它将自动使用灰色。您根本不需要计算颜色。
  • 您可以在accentColor层次结构中较高的环境中设置View,它将滴入所有后代。这样可以轻松为整个界面设置统一的强调色。

  • 在以下示例中,我将accentColor修饰符放在HStack上。在真实的应用程序中,您可能会在整个应用程序的根 View 上进行设置:
    struct ContentView : View {
        @State var chatMessage: String = ""
    
        var body: some View {
            HStack {
                TextField($chatMessage, placeholder: Text("Reply"))
                    .textFieldStyle(.roundedBorder)
                Button(action: sendMessage) {
                    Image(systemName: "arrow.up.circle")
                }
                    .disabled(!chatMessageIsValid)
            }
                .padding([.leading, .trailing], 10)
                .accentColor(.orange)
        }
    
        var chatMessageIsValid: Bool {
            return !chatMessage.isEmpty
        }
    
        func sendMessage() {
            chatMessage = ""
        }
    }
    

    同样,Matt将发送按钮提取为自己的类型的想法可能很聪明。它使用户可以轻松完成一些精美的事情,例如在用户单击时对其进行动画处理:

    button animation demo

    这是代码:
    struct ContentView : View {
        @State var chatMessage: String = ""
    
        var body: some View {
            HStack {
                TextField($chatMessage, placeholder: Text("Reply"))
                    .textFieldStyle(.roundedBorder)
                SendButton(action: sendMessage, isDisabled: chatMessage.isEmpty)
            }
                .padding([.leading, .trailing], 10)
                .accentColor(.orange)
        }
    
        func sendMessage() {
            chatMessage = ""
        }
    }
    
    struct SendButton: View {
        let action: () -> ()
        let isDisabled: Bool
    
        var body: some View {
                Button(action: {
                    withAnimation {
                        self.action()
                        self.clickCount += 1
                    }
                }) {
                    Image(systemName: "arrow.up.circle")
                        .rotationEffect(.radians(2 * Double.pi * clickCount))
                        .animation(.basic(curve: .easeOut))
                }
                    .disabled(isDisabled)
        }
    
        @State private var clickCount: Double = 0
    }
    

    关于swift - 根据禁用与否更改SwiftUI中按钮的颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56675897/

    相关文章:

    swift - 如何使用 Swift 从表格中的 HTML 类中检索标签

    ios - 为什么 "self"在我的 QueryOperation 中阻止来自 CloudKit 的数据

    ios - 如何跟踪使用 NSIndexPath 选择的单元格?

    swift - iOS 上的 ImageRenderer - 生成模糊图像

    ios - SwiftUI 耗费了我一上午的时间,只是构建了一个小按钮,请救救我

    swift - 在 Swift 中创建没有外部属性的结构/协议(protocol)/类

    ios - 视频缩略图需要 10-15 秒才能显示

    ios - 如何在SwiftUI中汇总过滤后的核心数据?

    core-data - 使用 FetchRequest 时如何在 PreviewProvider 中显示示例数据

    swiftui - TextField 更改后 NavigationLink 关闭