如何在SwiftUI中将对TextField的输入限制为仅接受0-10之间的数字?

时间:2020-11-09 20:35:51

标签: ios swift swiftui

我对这个问题有不同的回答,但我很困惑。我对Swift比较陌生。我目前正在为学校的高级项目工作。希望有人回答这个问题,但也会详细介绍。当前行为仅执行0-9。我不能让它做10号。

struct ContentView: View {
    
    // Private vars for tracking
    @State private var hoursSlept = 0;
    
    // *** What happens if the user enters something other than an integer/double?
    @State private var depressedMood = ""
    @State private var elevatedMood = ""
    @State private var anxietyMood = ""
    @State private var irritabilityMood = ""
    
    @State private var maxLength = 1;
    
    
    // Var for button
    @State private var enterButtonPress = false
    
    var body: some View {
        VStack {
            NavigationView {
                Form {
                    
                    
                    
                    // Hours slept last night (0-24)
                    Stepper(value: $hoursSlept, in: 0...24, label: {
                        Text("Hours slept last night: \(self.hoursSlept)")
                        
                    })
                    
                    TextField("Depression 0-10", text: $depressedMood)
                        .keyboardType(.numberPad)
                        .onReceive(Just(depressedMood)) {
                            guard !$0.isEmpty else {
                                self.depressedMood = ""
                                return
                            }
                            if let value = Int($0.filter(\.isWholeNumber).prefix(maxLength)) {
                                self.depressedMood = String(value)
                            }
                            
                        }
                    
                    
                    
                    TextField("Elevation 0-10", text: $elevatedMood)
                        .keyboardType(.numberPad)
                        .onReceive(Just(elevatedMood)) {
                            guard !$0.isEmpty else {
                                self.elevatedMood = ""
                                return
                            }
                            
                            if let value = Int($0.filter(\.isWholeNumber).prefix(maxLength)) {
                                self.elevatedMood = String(value)
                            }
                        }
                    
                    
                    
                    TextField("Anxiety 0-10", text: $anxietyMood)
                        .keyboardType(.numberPad)
                        .onReceive(Just(anxietyMood)) {
                            guard !$0.isEmpty else {
                                self.anxietyMood = ""
                                return
                            }
                            if let value = Int($0.filter(\.isWholeNumber).prefix(maxLength)) {
                                self.anxietyMood = String(value)
                            }
                        }
                    
                    
                    TextField("Irritability 0-10", text: $irritabilityMood)
                        .keyboardType(.numberPad)
                        .onReceive(Just(irritabilityMood)) {
                            guard !$0.isEmpty else {
                                self.irritabilityMood = ""
                                return
                            }
                            if let value = Int($0.filter(\.isWholeNumber).prefix(maxLength)) {
                                self.irritabilityMood = String(value)
                            }
                        }

4 个答案:

答案 0 :(得分:0)

这是一个可能的解决方案-使用~=并检查该值是否在范围内:

struct ContentView: View {
    @State private var depressedMood = ""

    var body: some View {
        TextField("Depression 0-10", text: $depressedMood)
            .keyboardType(.numberPad)
            .onReceive(Just(depressedMood)) {
                guard let value = Int($0), 0...10 ~= value else {
                    self.depressedMood = ""
                    return
                }
                self.depressedMood = String(value)
            }
    }
}

答案 1 :(得分:0)

您应该尝试使用自定义TextField,以便可以管理逻辑。然后,您可以将其绑定到所需的任何文本字段。

class TextBindingManager: ObservableObject {
    @Published var text = "" {
        didSet {
            guard let newValue = Int(text) else {
                text = oldValue
                return
            }
            
            if( !(newValue >= range.lowerBound) || !(newValue <= range.upperBound)) {
                text = oldValue
            }
        }
    }
    
    let range: Range<Int>

    init(limit: Range<Int> = 0..<10){
        range = limit
    }
}

然后可以通过绑定将其放置在您喜欢的任何地方

struct MyView: View {
    
    @ObservedObject var textBindingManager = TextBindingManager()
    
    var body: some View {
            
       TextField("", text: $textBindingManager.text, onEditingChanged: { _ in }, onCommit: {})
    }
}

答案 2 :(得分:0)

考虑到您已将字段的maxLength设置为1,这绝对是预期的行为。最简单的方法是在字段中添加出价管理器,检查输入的文本是否在您的范围内,否则将其值设置为最后一个值:

import SwiftUI

struct ContentView: View {
    @ObservedObject private var bindingManager = TextBindingManager(string: "")
    @State private var depressedMood = ""
    var body: some View {
        TextField("Depression 0-10", text: $bindingManager.string)
        .onChange(of: bindingManager.string) { newValue in
            // this allows the user to clear the field
            if bindingManager.string.isEmpty { return }
            guard let newValue = Int(bindingManager.string), 0...10 ~= newValue else {
                // this would allow the user to replace the current value
                // you can comment out this if you want to force the user to clear the contents using the delete backwards key before entering new value
                if let digit = bindingManager.string.last?.wholeNumberValue {
                    bindingManager.string = String(digit)
                    depressedMood = bindingManager.string
                    return
                }
                // this would leave the field unchanged if an invalud value is entered
                bindingManager.string = depressedMood
                depressedMood = bindingManager.string
                return
            }
            bindingManager.string = String(newValue)
            depressedMood = bindingManager.string
  
        }
        .keyboardType(.numberPad)
        .padding()
    }
}

class TextBindingManager: ObservableObject {
    @Published var string: String = ""
    init(string: String) { self.string = string }
}

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

Sample project

答案 3 :(得分:0)

您可以使用类似以下的简单内容:

struct ContentView: View {
    @State var depressedMood = ""
    var body: some View {
        VStack {
            TextField("0-10", text: $depressedMood)
                .keyboardType(.numberPad)
                .onChange(of: depressedMood) {
                    let txt = $0.filter("0123456789".contains)
                    if let num = Int(txt), num <= 10, txt.count <= 2 {
                        depressedMood = txt
                    } else {
                        depressedMood = String(txt.dropLast())
                    }
                }
        }
    }
}
相关问题