为什么将按钮嵌入到SwiftUI表单中后不起作用?

时间:2019-09-15 19:34:00

标签: swiftui

我正在构建SwitUI表单。我需要绘制一些自定义滑块。为此,我多次创建了一个包含在表单中的视图(SliderView)。我花了一些时间来管理Binding,以获取父视图中Sliders的值,但是我能够做到这一点:-) 我无法理解的一个大谜团是为什么我放置在子视图中的按钮在嵌入到Form中时不起作用。它们在VStack中可以正常工作。这里的代码:

//  SliderView.swift

import SwiftUI

struct SliderView: View {
    var name: String
    var min: Double
    var max: Double
    var step: Double
    var defaultValue: Double

    let numberFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.minimumFractionDigits = 0
        formatter.maximumFractionDigits = 2
        formatter.minimumIntegerDigits = 1
        return formatter
    }()


    @Binding var selectedValue: Double
    var body: some View {
        HStack{
            Text("\(name)")
            Slider(value: $selectedValue, in: self.min...self.max, step: self.step)
            Button(action: {
                if (self.selectedValue - self.step) >= self.min{
                    self.selectedValue = self.selectedValue - self.step
                }
            }) {
                Image(systemName:"minus.circle")
            }
            Text("\(numberFormatter.string(from: NSNumber(value: selectedValue)) ?? "")")
                .padding(5)
                .onAppear {
                    self.selectedValue = self.defaultValue
                }
            Button(action: {
                if (self.selectedValue + self.step) <= self.max{
                    self.selectedValue = self.selectedValue + self.step
                }
            }) {
                Image(systemName:"plus.circle")
            }


        }

    }
}

struct SliderView_Previews: PreviewProvider {
    @State static var myValue: Double = 1
    static var previews: some View {
        SliderView(name: "CPU", min: 1, max: 10, step: 0.5, defaultValue: 1, selectedValue: $myValue)
    }
}

现在,这是我正在构建的表单的一部分。代码会编译,滑块起作用,并且每个滑块的值都可以在父视图中看到。但是,逐步更新滑块的按钮不起作用(因为它们已嵌入在表单中)

//
//  ContentView.swift

import SwiftUI

struct ContentView: View {
    @State var selectedCPU: Double = 1
    @State var selectedRAM: Double = 1
    @State var selectedDisk: Double = 50
    var body: some View {

        NavigationView{
            Form{
                Section{
                    SliderView(name: "CPU", min: 1, max: 16, step: 1, defaultValue: selectedCPU, selectedValue: $selectedCPU)
                    SliderView(name: "RAM", min: 0.5, max: 128, step: 0.5, defaultValue: selectedRAM, selectedValue: $selectedRAM)
                    SliderView(name: "SSD", min: 20, max: 500, step: 10, defaultValue: selectedDisk, selectedValue: $selectedDisk)
                }
                Section{
                    Text("CPU: \(selectedCPU)")
                    Text("RAM: \(selectedRAM)")
                    Text("SSD: \(selectedDisk)")
                }
            }
        }


    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

只需在上方代码中将“ Form”替换为“ VStack”,按钮就可以正常工作。有人可以照亮吗?我认为这与表单中的不同层有关。当我尝试单击按钮时,似乎单击了带有滑块的整行,但没有任何反应。 我在MacOS 10.15 Beta(19A558d)中使用Xcode 11 GM 预先感谢!

2 个答案:

答案 0 :(得分:6)

尝试将buttonStyle修饰符添加到窗体中的按钮。这对我有用:

Button(action: {}, label: {Text("Test")})
    ­­­­­.buttonStyle(PlainButtonStyle())

答案 1 :(得分:1)

据我所知,表单行包含一个接受点击手势(例如按钮)的视图时,它们的行为会有所不同。当该行包含一个Button时,则当用户点击该按钮时,同一行中的所有其他内容也会收到点击手势。因此,在上面的示例中,并不是按钮不起作用,实际上是按钮都在接收轻击手势并执行了动作,但是由于代码中的逻辑有效地消除了其他按钮的影响,因此看起来好像他们没有工作。

为帮助说明这一点,这是我编写的一些测试代码:

    @State var count1 = 0
    @State var count2 = 0

    func buttonTest() -> some View {
        HStack {
            Button(action: {
                self.count1 += 1
            }) {
                Text("Button 1: \(count1)")
            }
            Spacer()
            Button(action: {
                self.count2 += 1
            }) {
                Text("Button 2: \(count2)")
            }
        }
    }

    var body: some View {
        VStack {
            buttonTest()
            Form {
                Section(header: Text("Test")) {
                    buttonTest()
                }
            }
        }
    }

如果您点击表格上方的任一按钮,它们将按预期独立工作,仅增加其自身的计数,但是如果您点击表格中的任一按钮或该行中的其他任何地方,则这两个按钮的动作都将执行并且都计数

我不确定苹果为什么要这样做,但我也正努力寻找解决此问题的方法。

编辑

由于Shauket Sheikh,有一个解决方案,但是它使代码重用不那么优雅。

因此,当Button在表单中时,您需要将代码放入.onTapGesture处理程序中,但是如果Button在Form中,则需要在action:处理程序中进行代码。< / p>

我真的希望这不是Apple在Forms上的长期立场:它与一次编写,随处使用的哲学背道而驰。