将@State变量作为参数传递,并在函数内部更改其值

huangapple go评论65阅读模式
英文:

Pass an @State variable as parameter and change its value inside a function

问题

I can provide the translation for the code portion you provided:

我试图验证文本字段,只允许输入数字、一个小数点或一个逗号。在下面的代码中,我有两个 `TextField``textFieldOne`  `textFieldTwo`,在 `textFieldOne` 中,我通过调用 `validateField()` 方法来验证字段,一切都按预期工作,因为我在 `validateField()` 方法内修改了它的值。但我试图让 `validateField()` 方法更加模块化,并能够传递一个 `State` 变量,以便可以在多个字段中使用它,以避免代码重复,但我一直没有找到一种在 `validateField()` 方法中将 `State` 变量作为参数传递的方法。我尝试将其传递为 `validateField(textFieldName: Binding<String> ,newValue:String)`,但我收到错误消息,说它无法将类型 `'String'` 转换为预期的类型 `'Binding<String>`

如何将 `@State`  `textFieldOne`  `textFieldTwo` 作为参数传递给 `validateField()` 方法?

再次强调,我想要的是能够在每个字段的 `.onChange` 修饰符内调用 `validateField()` 方法,类似于这样... `validateField(fieldName:textFieldOne, newValue: newValue)`。基本上,使该方法可重用。

Please note that I've translated the code portion you provided. If you have any further questions or need assistance with this code, please feel free to ask.

英文:

I'm trying to validate textFields to only allow numbers, a single period, or a single comma. In the code below I have two TextFields, textFieldOne and textFieldTwo, in textFieldOne I'm validating the field by calling the validateField() method, everything works as expected for textFieldOne since I'm modifying its value inside the validateField() method, but what I'm trying to do is make the validateField() method more modular and be able to pass a State variable to be able to use it with multiple fields to avoid code duplication but I haven't been able to figure out a way to pass the State variable as a parameter in the validateField() method. I tried passing it as validateField(textFieldName: Binding<String> ,newValue:String) but I got errors saying that it couldn't convert type 'String' to expected type 'Binding<String>.

How can I pass @State textFieldOne and textFieldOne respectably as a parameter in the validateField() method?

Again, what I'm trying to do is be able to call the validateField() method inside the .onChange modifier of each field, something like this... validateField(fieldName:textFieldOne, newValue: newValue). Basically, make the method reusable.

	struct TextFieldNumbersOnly: View {
		@State private var textFieldOne = ""
		@State private var textFieldTwo = ""
		
		var body: some View {
			Form{
				TextField("field one", text: $textFieldOne)
					.keyboardType(.decimalPad)
					.onChange(of: textFieldOne){newValue in
						validateField(newValue: newValue)
					}
				
				TextField("field two", text: $textFieldTwo)
					.keyboardType(.decimalPad)
					.onChange(of: textFieldTwo){newValue in
						//validateField(newValue: newValue)
					}
			}

		}
		
		func validateField(newValue:String){
			let periodCount = newValue.components(separatedBy: ".").count - 1
			let commaCount = newValue.components(separatedBy: ",").count - 1
			
			if newValue.last == "." && periodCount > 1 || newValue.last == "," && commaCount > 1{
				//it's a second period or comma, remove it
				textFieldOne = String(newValue.dropLast())
			}else{
				let filtered = newValue.filter { "0123456789.,".contains($0) }
				if filtered != newValue{
					self.textFieldOne = filtered
				}
			}
		}
	}

答案1

得分: 0

你可以尝试这种替代方法,以实现你想要的效果,只允许文本字段包含数字、一个小数点或一个逗号,并使函数 validateField(...) 更加模块化。

这种方法简单地使用了一个修改过的函数 validateField(...),该函数返回已验证的字符串,如示例代码所示。它很干净,并且执行函数应该执行的操作,即接受一个 String 输入并返回一个经过验证的输出。

struct TextFieldNumbersOnly: View {
    @State private var textFieldOne = ""
    @State private var textFieldTwo = ""
    
    var body: some View {
        Form {
            TextField("field one", text: $textFieldOne)
                .keyboardType(.decimalPad)
                .onChange(of: textFieldOne){ newValue in
                    textFieldOne = validateField(newValue) // <-- 这里
                }
            
            TextField("field two", text: $textFieldTwo)
                .keyboardType(.decimalPad)
                .onChange(of: textFieldTwo){ newValue in
                    textFieldTwo = validateField(newValue) // <-- 这里
                }
        }
    }

    func validateField(_ newValue: String) -> String {  // <-- 这里
        let periodCount = newValue.components(separatedBy: ".").count - 1
        let commaCount = newValue.components(separatedBy: ",").count - 1
        
        if newValue.last == "." && periodCount > 1 || newValue.last == "," && commaCount > 1 {
            // 这是第二个小数点或逗号,移除它
            return String(newValue.dropLast())  // <-- 这里
        } else {
            let filtered = newValue.filter { "0123456789., ".contains($0) }
            if filtered != newValue {
                return filtered // <-- 这里
            }
        }
        return newValue // <-- 这里
    }
}

希望这对你有所帮助。如果有其他问题,请随时提问。

英文:

You could try this alternative approach, to achieve what you want, ...to validate textFields
to only allow numbers, a single period, or a single comma

and to make the function validateField(...) more modular.

The approach simply uses a modified function validateField(...) that
returns the validated String, as shown in the example code.
It's clean and do what the function is supposed to do,
take a String input and returns a validated one as output.

struct TextFieldNumbersOnly: View {
    @State private var textFieldOne = &quot;&quot;
    @State private var textFieldTwo = &quot;&quot;
    
    var body: some View {
        Form {
            TextField(&quot;field one&quot;, text: $textFieldOne)
                .keyboardType(.decimalPad)
                .onChange(of: textFieldOne){ newValue in
                    textFieldOne = validateField(newValue) // &lt;-- here
                }
            
            TextField(&quot;field two&quot;, text: $textFieldTwo)
                .keyboardType(.decimalPad)
                .onChange(of: textFieldTwo){ newValue in
                    textFieldTwo = validateField(newValue) // &lt;-- here
                }
        }
    }

    func validateField(_ newValue: String) -&gt; String {  // &lt;-- here
        let periodCount = newValue.components(separatedBy: &quot;.&quot;).count - 1
        let commaCount = newValue.components(separatedBy: &quot;,&quot;).count - 1
        
        if newValue.last == &quot;.&quot; &amp;&amp; periodCount &gt; 1 || newValue.last == &quot;,&quot; &amp;&amp; commaCount &gt; 1 {
            //it&#39;s a second period or comma, remove it
            return String(newValue.dropLast())  // &lt;-- here
        } else {
            let filtered = newValue.filter { &quot;0123456789.,&quot;.contains($0) }
            if filtered != newValue{
                return filtered // &lt;-- here
            }
        }
        return newValue // &lt;-- here
    }
}

答案2

得分: 0

创建一个新的视图,并在其中放置一个文本字段和验证。请注意,SwiftUI 的设计是在 onSubmit 中进行验证,而不是在 onChange 中进行验证,以允许粘贴。然后使用两个这样的视图。

TextFieldNumbersOnly(text: $one)
TextFieldNumbersOnly(text: $two)

struct TextFieldNumbersOnly: View {
    @Binding private var text: String
    
    var body: some View {
        
        TextField("字段", text: $text)
            .keyboardType(.decimalPad)
            .onSubmit {
                validate()
            }
    }
            
    func validate(){
    ...
英文:

Create a new View and put one TextField and the validation in it. FYI SwiftUI is designed to do validation in onSubmit instead of onChange to allow pasting. Then use two of these Views.

TextFieldNumbersOnly(text: $one)
TextFieldNumbersOnly(text: $two)

struct TextFieldNumbersOnly: View {
    @Binding private var text: String
    
    var body: some View {
        
        TextField(&quot;field&quot;, text: $text)
            .keyboardType(.decimalPad)
            .onSubmit {
                validate()
            }
    }
            
    func validate(){
…

huangapple
  • 本文由 发表于 2023年6月9日 11:03:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76436939.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定