SwiftUI应用按钮逻辑问题:Submit按钮标签切换失效
SwiftUI Submit按钮标签切换逻辑修复
问题场景
我用SwiftUI开发的应用里,通过单个结构体从数组生成多个mainButton,还有一个Submit按钮。想要实现的逻辑是:
- 当某个
mainButton被选中(已实现颜色和尺寸变化),且Submit按钮被点击过一次后,Submit按钮的标签切换为向上箭头图标; - 直到用户点击另一个
mainButton(该按钮完成颜色和尺寸变化),Submit按钮才恢复为“Submit”文本。
目前其他功能正常,但Submit按钮的标签切换逻辑失效。我是Swift/SwiftUI新手,希望用基础的条件判断和变量实现该逻辑,以下是简化版代码:
// // AddView.swift // WriteOn // // Created by Maurizio Zappettini on 2/11/23. // import SwiftUI struct AddView: View { @State private var typeofMessageGeneric: String = "" @State private var lastButtonTapped: String = "" @State private var buttonCount: Int = 0 let buttonData = [ (mainButtonText: "A", mainButtonValue: "a"), (mainButtonText: "B", mainButtonValue: "b"), (mainButtonText: "C", mainButtonValue: "c"), (mainButtonText: "D", mainButtonValue: "d"), ] var body: some View { ZStack { // Using ZStack for background gradient Rectangle() .frame( minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading) .foregroundColor(.clear) .background(LinearGradient(colors: [.blue, .purple], startPoint: .top, endPoint: .bottom)) VStack { //Master VStack VStack { //Headline Text("Test View") .font(.headline) .padding() } GeometryReader { geometry in // Debug alignment VStack(alignment: .center) { //TextBox Rectangle() .fill(Color.cyan) .cornerRadius(20) .frame(width: geometry.size.width * 0.8, height: 250, alignment: .center) .overlay( HStack(alignment: .top){ VStack { Spacer() } ScrollView { VStack(alignment: .center) { Text("getResponsePlaceHolder") .foregroundColor(.black) .frame(minWidth: 0, maxWidth: .infinity, alignment: .center) .layoutPriority(2) } } VStack{ ShareLink(item: "nothing"){ Image(systemName: "square.and.arrow.up") .resizable() .scaledToFit() .frame(width: 25, height: 25) .foregroundColor(.black) } } VStack{ Spacer() } } .frame(height: geometry.size.height * 0.6) // find way to make it refer to actual box and not whole screen ) .frame(maxWidth: .infinity, maxHeight: .infinity) } //Vstack Top } //Geo Reader Spacer(minLength: 50 ) ScrollView{ VStack { //Buttons ForEach(buttonData, id: \.mainButtonValue) { data in mainButton(typeofMessageGeneric: self.$typeofMessageGeneric, lastButtonTapped: self.$lastButtonTapped, buttonCount: self.$buttonCount, mainButtonText: data.mainButtonText, mainButtonValue: data.mainButtonValue) } } //Button Vstack end } VStack{ //Footer submitButton() } } } } func submitButton() -> some View { return Button(action: getResponse) { if self.typeofMessageGeneric == self.lastButtonTapped && self.buttonCount == 0 { Text("Submit") .font(.system(size: 20)) .foregroundColor(.white) .padding() .background(Color.blue) .cornerRadius(10) } else { Image(systemName: "arrow.clockwise.circle") .font(.system(size: 30)) .foregroundColor(.white) .padding() .background(Color.blue) .cornerRadius(10) } } } // Create main buttons struct mainButton: View { @Binding var typeofMessageGeneric: String // Bind the variable inside this struct with the same one inside the ContentView struct @Binding var lastButtonTapped: String // Not currently used -- implement later if needed @Binding var buttonCount:Int var mainButtonText:String var mainButtonValue:String var body: some View { Button(action: { self.typeofMessageGeneric = mainButtonValue self.lastButtonTapped = mainButtonValue buttonCount = 0 if self.typeofMessageGeneric == mainButtonValue{ buttonCount = 1 } else { buttonCount = 0 } }) { Text(mainButtonText) Text(String(buttonCount)) // testing only } .font(.system(size: 20)) .foregroundColor(.white) .padding() .background(self.mainButtonValue == self.typeofMessageGeneric ? Color.teal : Color.purple) .cornerRadius(10) .scaleEffect(self.mainButtonValue == self.typeofMessageGeneric ? 1.12 : 1) .animation(.easeOut, value: 2) } } func getResponse() { } } struct AddView_Previews: PreviewProvider { static var previews: some View { AddView() } }
问题分析与修复
你的逻辑失效核心是状态变量管理混乱:buttonCount和lastButtonTapped冗余且逻辑冲突,同时缺少专门记录Submit是否被点击的状态变量。下面是分步修复方案:
步骤1:新增核心状态变量
在AddView里添加一个@State变量,专门记录Submit按钮的点击状态:
@State private var isSubmitTapped = false
步骤2:简化mainButton的点击逻辑
移除冗余的buttonCount和lastButtonTapped,点击按钮时只需更新选中状态,并重置Submit的点击标记:
struct mainButton: View { @Binding var typeofMessageGeneric: String @Binding var isSubmitTapped: Bool // 绑定Submit状态,点击新按钮时重置 var mainButtonText: String var mainButtonValue: String var body: some View { Button(action: { typeofMessageGeneric = mainButtonValue isSubmitTapped = false // 切换按钮时,让Submit恢复文本 }) { Text(mainButtonText) } .font(.system(size: 20)) .foregroundColor(.white) .padding() .background(mainButtonValue == typeofMessageGeneric ? Color.teal : Color.purple) .cornerRadius(10) .scaleEffect(mainButtonValue == typeofMessageGeneric ? 1.12 : 1) .animation(.easeOut, value: typeofMessageGeneric) // 绑定选中状态触发动画 } }
步骤3:修正Submit按钮的判断逻辑
用typeofMessageGeneric(当前选中的按钮)和isSubmitTapped(是否点击过Submit)作为判断条件,逻辑更清晰:
func submitButton() -> some View { Button(action: { isSubmitTapped = true // 点击Submit后标记状态 getResponse() }) { // 没选中按钮 或 没点击过Submit → 显示文本 if typeofMessageGeneric.isEmpty || !isSubmitTapped { Text("Submit") .font(.system(size: 20)) .foregroundColor(.white) .padding() .background(Color.blue) .cornerRadius(10) } else { // 选中按钮且点击过Submit → 显示向上箭头 Image(systemName: "arrow.up.circle") .font(.system(size: 30)) .foregroundColor(.white) .padding() .background(Color.blue) .cornerRadius(10) } } .disabled(typeofMessageGeneric.isEmpty) // 可选:未选中按钮时禁用Submit }
步骤4:更新mainButton的调用
把新增的isSubmitTapped绑定传入:
mainButton(typeofMessageGeneric: $typeofMessageGeneric, isSubmitTapped: $isSubmitTapped, mainButtonText: data.mainButtonText, mainButtonValue: data.mainButtonValue)
完整修正代码
import SwiftUI struct AddView: View { @State private var typeofMessageGeneric: String = "" @State private var isSubmitTapped = false // 记录Submit是否被点击 let buttonData = [ (mainButtonText: "A", mainButtonValue: "a"), (mainButtonText: "B", mainButtonValue: "b"), (mainButtonText: "C", mainButtonValue: "c"), (mainButtonText: "D", mainButtonValue: "d"), ] var body: some View { ZStack { Rectangle() .frame(maxWidth: .infinity, maxHeight: .infinity) .foregroundColor(.clear) .background(LinearGradient(colors: [.blue, .purple], startPoint: .top, endPoint: .bottom)) VStack { VStack { Text("Test View") .font(.headline) .padding() } GeometryReader { geometry in VStack(alignment: .center) { Rectangle() .fill(Color.cyan) .cornerRadius(20) .frame(width: geometry.size.width * 0.8, height: 250) .overlay( HStack(alignment: .top){ Spacer() ScrollView { VStack(alignment: .center) { Text("getResponsePlaceHolder") .foregroundColor(.black) .frame(maxWidth: .infinity, alignment: .center) .layoutPriority(2) } } VStack{ ShareLink(item: "nothing"){ Image(systemName: "square.and.arrow.up") .resizable() .scaledToFit() .frame(width: 25, height: 25) .foregroundColor(.black) } } Spacer() } .frame(height: geometry.size.height * 0.6) ) } } Spacer(minLength: 50) ScrollView{ VStack { ForEach(buttonData, id: \.mainButtonValue) { data in mainButton(typeofMessageGeneric: $typeofMessageGeneric, isSubmitTapped: $isSubmitTapped, mainButtonText: data.mainButtonText, mainButtonValue: data.mainButtonValue) } } } VStack{ submitButton() } } } } func submitButton() -> some View { Button(action: { isSubmitTapped = true getResponse() }) { if typeofMessageGeneric.isEmpty || !isSubmitTapped { Text("Submit") .font(.system(size: 20)) .foregroundColor(.white) .padding() .background(Color.blue) .cornerRadius(10) } else { Image(systemName: "arrow.up.circle") .font(.system(size: 30)) .foregroundColor(.white) .padding() .background(Color.blue) .cornerRadius(10) } } .disabled(typeofMessageGeneric.isEmpty) } struct mainButton: View { @Binding var typeofMessageGeneric: String @Binding var isSubmitTapped: Bool var mainButtonText: String var mainButtonValue: String var body: some View { Button(action: { typeofMessageGeneric = mainButtonValue isSubmitTapped = false }) { Text(mainButtonText) } .font(.system(size: 20)) .foregroundColor(.white) .padding() .background(mainButtonValue == typeofMessageGeneric ? Color.teal : Color.purple) .cornerRadius(10) .scaleEffect(mainButtonValue == typeofMessageGeneric ? 1.12 : 1) .animation(.easeOut, value: typeofMessageGeneric) } } func getResponse() { // 这里添加Submit后的业务逻辑 } } struct AddView_Previews: PreviewProvider { static var previews: some View { AddView() } }
逻辑说明
- 状态清晰化:用
isSubmitTapped专门记录Submit的点击状态,避免多个变量混乱; - 按钮切换逻辑:点击新的
mainButton时,自动重置isSubmitTapped,让Submit恢复文本; - Submit显示逻辑:
- 未选中按钮或未点击Submit → 显示“Submit”文本;
- 已选中按钮且点击过Submit → 显示向上箭头图标;
- 简化冗余代码:移除了无用的
buttonCount和lastButtonTapped,减少状态维护成本。
内容的提问来源于stack exchange,提问作者mzo
相关产品推荐
相关产品推荐

