SwiftUI 中的按钮处理
Button handling in SwiftUI
在 SwiftUI
应用程序中,我有几个按钮(让我们以 3 为例)。其中一个已突出显示。
当我点击一个非突出显示的按钮时,之前突出显示的按钮切换为非突出显示,并且点击的按钮变为突出显示。如果我点击已经突出显示的按钮,什么也不会发生。
这个场景很简单,我有一个 highlighBtn 变量,当点击一个按钮时 highlighBtn 获取点击按钮的值。当下一次点击碰巧关闭先前突出显示的按钮时,将使用此变量。
这个循环没问题,但是问题出在第一次点击的时候。由于某些原因,事情不起作用。
这就是我处理 highlighBtn 变量创建的方式:
class ActiveButton: ObservableObject {
@Published var highlighBtn = Button(....)
}
@StateObject var box = ActiveButton()
点击按钮时的相关代码如下:
@EnvironmentObject var box: ActiveButton
....
Button(action: {
// Toggle off the previously highlighted button.
box.highlighBtn.highLight = false
.... some useful processing ....
box.highlighBtn = self
})
我应该给出一个细节:如果我点击突出显示的按钮开始,那么一切正常。
我尝试了各种方法来解决这个看似简单的问题,但都失败了。
第一种方法是尝试初始化 highlighBtn 变量。
第二个是尝试模拟点击突出显示的按钮。
我一定是漏掉了一些简单的东西。
欢迎任何提示。
进一步调查后.....
我创建了一个演示应用程序来暴露我的问题。
由于我缺乏使用 GitHub
的练习,我花了一些时间,但现在可用 here.
为此,我在 Xcode
中创建了一个 SwiftUI
应用程序。
在SceneDelegate.swift中,紧接此行的四行代码已根据此应用程序的需要进行了自定义:
// Create the SwiftUI view that provides the window contents.
除此之外,我所做的一切都在文件 ContentView.swift.
中
为要看的人节省一些时间;这是直截了当的方法(即我面临的问题)。
运行 应用程序(我是在 iPhone 7 上做的)。您会看到七个按钮出现。其中一个(随机)将突出显示。从突出显示的按钮开始,根据需要依次点击几个按钮。您将看到该应用程序应该如何工作。
(关闭后)运行 应用程序第二次。这次您还将根据需要多次连续点击几个按钮;但首先点击一个未突出显示的按钮。此时你会看到问题出现。
这是您问题第一部分的解决方案:最后一个点击的三个按钮会在背景中突出显示:
import SwiftUI
struct ContentView: View {
enum HighlightTag {
case none, first, second, third
}
@State private var highlighted = HighlightTag.none
var body: some View {
VStack {
Button("First") {
highlighted = .first
}.background(
Color.accentColor.opacity(
highlighted == .first ? 0.2 : 0.0
)
)
Button("Second") {
highlighted = .second
}.background(
Color.accentColor.opacity(
highlighted == .second ? 0.2 : 0.0
)
)
Button("Third") {
highlighted = .third
}.background(
Color.accentColor.opacity(
highlighted == .third ? 0.2 : 0.0
)
)
}
}
}
更新:
在 GitHub 上查看了您的示例代码后,我试图理解您的代码,尝试进行一些简化并试图找到可行的解决方案。
以下是一些意见:
- “var butnsPool”前面的属性“@State”不需要且容易混淆。
- “var initialHilight”前面的属性“@State”不需要,容易混淆。
- 您的 ActiveButton 存储了所选按钮视图的副本,因为它是一个结构,这可能是出现奇怪行为的主要原因。
- 你的 ObservableObject 中的 needInit 至少闻起来很糟糕。如果你真的需要初始化一些东西,你可以考虑在你的 ContentView 中使用一些 .onAppear() 修饰符。
- 可能不需要使用.environmentObject 和@EnvironmentObject。您可以考虑使用参数和@ObsservedObject
- 如果仅在内部使用,可能根本不需要 ActiveButton。您可以考虑使用带有所选按钮名称的@State
- 你的 BtnTxtView 没问题,但如果你想为过渡设置动画,请考虑用一些可动画的属性替换条件 (func
if
)。
根据您的代码,我创建了一个更简单且有效的解决方案。
我删除了 ActiveButton class 和 BttnView 结构。
我用这个替换了 ContentView:
struct ContentView: View {
var butnsPool: [String]
var initialHilight: Int
@State var selectedBox: String = ""
var body: some View {
ForEach(butnsPool, id: \.self) { buttonName in
Button(action: {
selectedBox = buttonName
})
{
BtnTxtView(theLabel: buttonName,
highLight: buttonName == selectedBox)
}
}.onAppear {
selectedBox = butnsPool[initialHilight]
}
}
}
在 SwiftUI
应用程序中,我有几个按钮(让我们以 3 为例)。其中一个已突出显示。
当我点击一个非突出显示的按钮时,之前突出显示的按钮切换为非突出显示,并且点击的按钮变为突出显示。如果我点击已经突出显示的按钮,什么也不会发生。
这个场景很简单,我有一个 highlighBtn 变量,当点击一个按钮时 highlighBtn 获取点击按钮的值。当下一次点击碰巧关闭先前突出显示的按钮时,将使用此变量。
这个循环没问题,但是问题出在第一次点击的时候。由于某些原因,事情不起作用。
这就是我处理 highlighBtn 变量创建的方式:
class ActiveButton: ObservableObject {
@Published var highlighBtn = Button(....)
}
@StateObject var box = ActiveButton()
点击按钮时的相关代码如下:
@EnvironmentObject var box: ActiveButton
....
Button(action: {
// Toggle off the previously highlighted button.
box.highlighBtn.highLight = false
.... some useful processing ....
box.highlighBtn = self
})
我应该给出一个细节:如果我点击突出显示的按钮开始,那么一切正常。
我尝试了各种方法来解决这个看似简单的问题,但都失败了。
第一种方法是尝试初始化 highlighBtn 变量。 第二个是尝试模拟点击突出显示的按钮。
我一定是漏掉了一些简单的东西。 欢迎任何提示。
进一步调查后.....
我创建了一个演示应用程序来暴露我的问题。
由于我缺乏使用 GitHub
的练习,我花了一些时间,但现在可用 here.
为此,我在 Xcode
中创建了一个 SwiftUI
应用程序。
在SceneDelegate.swift中,紧接此行的四行代码已根据此应用程序的需要进行了自定义:
// Create the SwiftUI view that provides the window contents.
除此之外,我所做的一切都在文件 ContentView.swift.
中为要看的人节省一些时间;这是直截了当的方法(即我面临的问题)。
运行 应用程序(我是在 iPhone 7 上做的)。您会看到七个按钮出现。其中一个(随机)将突出显示。从突出显示的按钮开始,根据需要依次点击几个按钮。您将看到该应用程序应该如何工作。
(关闭后)运行 应用程序第二次。这次您还将根据需要多次连续点击几个按钮;但首先点击一个未突出显示的按钮。此时你会看到问题出现。
这是您问题第一部分的解决方案:最后一个点击的三个按钮会在背景中突出显示:
import SwiftUI
struct ContentView: View {
enum HighlightTag {
case none, first, second, third
}
@State private var highlighted = HighlightTag.none
var body: some View {
VStack {
Button("First") {
highlighted = .first
}.background(
Color.accentColor.opacity(
highlighted == .first ? 0.2 : 0.0
)
)
Button("Second") {
highlighted = .second
}.background(
Color.accentColor.opacity(
highlighted == .second ? 0.2 : 0.0
)
)
Button("Third") {
highlighted = .third
}.background(
Color.accentColor.opacity(
highlighted == .third ? 0.2 : 0.0
)
)
}
}
}
更新: 在 GitHub 上查看了您的示例代码后,我试图理解您的代码,尝试进行一些简化并试图找到可行的解决方案。
以下是一些意见:
- “var butnsPool”前面的属性“@State”不需要且容易混淆。
- “var initialHilight”前面的属性“@State”不需要,容易混淆。
- 您的 ActiveButton 存储了所选按钮视图的副本,因为它是一个结构,这可能是出现奇怪行为的主要原因。
- 你的 ObservableObject 中的 needInit 至少闻起来很糟糕。如果你真的需要初始化一些东西,你可以考虑在你的 ContentView 中使用一些 .onAppear() 修饰符。
- 可能不需要使用.environmentObject 和@EnvironmentObject。您可以考虑使用参数和@ObsservedObject
- 如果仅在内部使用,可能根本不需要 ActiveButton。您可以考虑使用带有所选按钮名称的@State
- 你的 BtnTxtView 没问题,但如果你想为过渡设置动画,请考虑用一些可动画的属性替换条件 (func
if
)。
根据您的代码,我创建了一个更简单且有效的解决方案。
我删除了 ActiveButton class 和 BttnView 结构。 我用这个替换了 ContentView:
struct ContentView: View {
var butnsPool: [String]
var initialHilight: Int
@State var selectedBox: String = ""
var body: some View {
ForEach(butnsPool, id: \.self) { buttonName in
Button(action: {
selectedBox = buttonName
})
{
BtnTxtView(theLabel: buttonName,
highLight: buttonName == selectedBox)
}
}.onAppear {
selectedBox = butnsPool[initialHilight]
}
}
}