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.

为要看的人节省一些时间;这是直截了当的方法(即我面临的问题)。

  1. 运行 应用程序(我是在 iPhone 7 上做的)。您会看到七个按钮出现。其中一个(随机)将突出显示。从突出显示的按钮开始,根据需要依次点击几个按钮。您将看到该应用程序应该如何工作。

  2. (关闭后)运行 应用程序第二次。这次您还将根据需要多次连续点击几个按钮;但首先点击一个未突出显示的按钮。此时你会看到问题出现。

这是您问题第一部分的解决方案:最后一个点击的三个按钮会在背景中突出显示:

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]
        }
    }
}