SwiftUI 中 Stepper 的奇怪行为

Posted

技术标签:

【中文标题】SwiftUI 中 Stepper 的奇怪行为【英文标题】:Strange Behavior of Stepper in SwiftUI 【发布时间】:2020-03-16 12:28:08 【问题描述】:

我想使用 onIncrement 和 onDecrement 在手动(非绑定)模式下使用 Stepper 视图。当我尝试实现下限和上限时,会有一个奇怪的行为,例如。年龄值不低于 1 或高于 10。

如果你尝试下面的代码,你可以在它已经有值“1”之后按两次“-”。它并没有像预期的那样低于 1,但是在另外两次按下“-”按钮后,“-”按钮突然被禁用。如果您然后按“+”,则不会发生任何事情。仅在再按 2 次“+”后,计数器才会按预期做出反应并变为 2。

这是一个错误吗?

struct StepperTest: View 
    @State private var age = 5

    var body: some View 
        VStack 
            Stepper("Enter your age", onIncrement: 
                if self.age < 10 
                    self.age += 1
                    print("Adding to age")
                
            , onDecrement: 
                guard self.age > 1 else  return 
                self.age -= 1
                print("Subtracting from age")
            )

            Text("Your age is \(age)")
        
    

【问题讨论】:

你为什么不想为此使用绑定? @MojtabaHosseini:因为我想要完全控制 完全控制什么?您已经可以访问editingChange,并且可以检测到女巫键被触摸。你还需要什么? 主要原因是,我想使用类似 Redux 的架构,其中状态仅由单独模块中的操作更改。使用绑定,可以在各种视图中修改状态。 这就是所谓的单向数据流架构,和这个没有冲突。 【参考方案1】:

递增后检查和重置值似乎可行:

Stepper("Enter your age", onIncrement: 
                    self.age += 1
                    if self.age > 10 self.age = 10
                
            , onDecrement: 
                self.age -= 1
                if self.age < 1 self.age = 1 
            )

【讨论】:

【参考方案2】:

我认为这里是解释:

/// 如果尝试递增,onIncrement 将被初始化为 nil /// value 将无效。同样,onDecrement 将被初始化 /// 到nil 如果尝试减少value 将无效。

如果你尝试

Stepper("Enter your age", onIncrement: 
    print("Adding to age")
, onDecrement: 
    print("Subtracting from age")
)

...您会看到步进器进入了与您描述的相同的状态,因此 Apple 跟踪步进器视图的重建,如果用户对步进器的操作没有启动重建(即无效),它会自行禁用。

另一个问题是为什么不是一次...

【讨论】:

我不完全了解您将如何使用它。我希望有这两个处理程序 onIncrement 和 onDecrement 以及两个属性来启用/禁用加号和减号按钮... 这是 Apple 的一个问题 )),但这是一个记录在案的行为。 我认为这是一个错误。即使我的onIncrementonDecrement 中没有任何if/else 逻辑,我也会得到同样的怪异行为。它只是停止并使“+”或“-”变灰。然后,如果您点击另一个进入错误的方向。该评论语法错误且难以理解。【参考方案3】:

我看到了同样的事情。在我看来,这绝对是苹果方面的一个错误。作为提到的评论者之一,您可以使用 onEditingChanged 参数。这应该为您提供所需的所有功能。随着绑定变量随步进器输入而变化,您可以采取行动。它看起来像这样:

Stepper(value: $age, in: 1...10, step: 1, onEditingChanged:  didChange in
        // take some action or make a calculation
) 

        Text("Your age is \(age)")

【讨论】:

【参考方案4】:

我看到了与在 Xcode 12.5.1 中使用 ios 14.5 描述的类似行为。我发现了这个描述错误的开放雷达:https://openradar.appspot.com/FB7669491

在我的例子中,我在初始化Stepper 时直接将视图模型中的函数作为onIncrementonDecrement 参数传递:

Stepper("Label", onIncrement: viewModel.increment, onDecrement: viewModel.decrement)

基于读取雷达,当前问题是由将函数在视图之外作为这些参数的值传递的。将我的代码更改为此解决了我的问题:

Stepper("Label", onIncrement:  viewModel.increment , onDecrement:  viewModel.decrement )

【讨论】:

以上是关于SwiftUI 中 Stepper 的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI:NavigationLink 奇怪的行为

SwiftUI 奇怪的动画行为与 systemImage

在 SwiftUI 视图中的 TextField 后面使用多个 SecureField 时的奇怪行为

如何在 SwiftUI 中将 Stepper 数据保存到 UserDefaults?

SwiftUI:onAppear 的奇怪行为

14:SwiftUI-Stepper