我有一个带有发送按钮的文本字段,它是一个系统图像箭头.我希望图像的前景色根据文本字段是否为空而改变.(即,按钮为灰色,如果文本字段为空,则该按钮被禁用.如果文本字段文本的计数为>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.但是,由于状态的变化,在键入一个字符后,您将被踢出编辑文本字段,您需要再次 Select 文本字段以继续键入.有没有更好的方法来解决这个问题.禁用修改器?

推荐答案

我猜你想要这个:

demo

可以为按钮 colored颜色 添加计算(computed)属性,并将该属性传递给按钮的foregroundColor修改器.也可以在HStack周围使用单个padding修改器,而不是在其子视图上使用单独的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 = ""
    }
}

However,这里根本不应该使用foregroundColor修饰符.你应该使用accentColor修饰符.使用accentColor有两个好处:

  • Button启用时,Image将自动使用环境的accentColor,当Button禁用时,Image将自动使用环境的accentColor.你根本不需要计算 colored颜色 .

  • 您可以在View层次 struct 的较高位置设置环境中的accentColor,它将向下渗透到所有后代.这使得为整个界面设置统一的强调色变得很容易.

在下面的示例中,我将accentColor修饰符放在HStack上.在真正的应用程序中,您可能会在整个应用程序的根视图上设置它:

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 = ""
    }
}

发送到马特自己的 idea ,也可能是马特的智能按钮类型.它可以轻松地做一些漂亮的事情,比如在用户单击它时为其设置动画:

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相关问答推荐

可编码:将字符串解码为自定义类型(ISO 8601日期,无时间组件)

在swift静态var扩展中,如何或可以访问和返回具体类?

为表单部分赋予背景 colored颜色 /渐变

启用完成并发判断以及如何解决警告(续)

运行异步任务串行运行

为什么第二项任务不在第一项任务完成之前开始?(并发队列)

查找数组中 ** 元素 ** 的属性的最小值和最大值

有条件地在同一视图上设置两个不同的过渡

如何在 Vapor 中制作可选的查询过滤器

如何使 onKeyPress 与 TextField 快速配合使用?

BLE 在 ESP32 和 Iphone 之间发送字符串

如何在 swiftui 中设置给定字符串类型日期的日期倒计时?

try 制作一个 Swift 扩展来替换字符串中的多次出现

自定义选取器的出现导致其他视图重新排列

Reality Composer Tap Trigger 问题

如何使用 Date.ParseStrategy 在 Swift 5.6 中将字符串解析为日期?

在 Swift 框架中加载资源(例如故事板)

CMutablePointer - 如何访问它?

是 swift 中另一个日期的同一周、月、年的日期

修复 Swift 3 中的警告C-style for Statement is deprecated