即时编辑 SwiftUI TextField
Editing a SwiftUI TextField on the fly
我希望能够在用户逐字符键入时编辑文本字段。我希望能够获取一个数字字段并在用户输入时输入:
- 过滤掉非数字字符并return仅返回已输入的有效字符。
- 格式化数字,以便在用户输入时得到相反的数字。即 120.36
将显示为:
0.01
0.12
1.20
12.03
120.36
如果用户输入了无效字符,则 return 不包含无效字符的字符串。
我对如何捕获 TextField、编辑它以及 return 它的格式如我所展示的感到困惑。
我已经走到这一步了:(不远了:-)
我已经在 Whosebug 上尝试了很多解决方案,但 none 似乎让我到达了我想去的地方..
onEditChange
变化时
等等
构造 SwiftUIView:视图 {
@State var amount: String = "0.00"
var body: some View {
TextField(
"Enter amount here ",
text: $amount
)
}
}
我怀疑我的要求太宽泛了,可能有点要求为我做程序的味道。事实并非如此,但也许我可以再缩小范围。
无论如何,我能够达到我想要的结果。我认为这是一个巨大的 KLUDGE,但这是我所能想到的。
首先是我的 SwiftUI 视图:
struct SwiftUIView: View {
@State var someText: String = "0.00"
@State var oldText: String = ""
@State var amount: Double = 0.00
var body: some View {
VStack {
TextField("Enter some text here", text: $someText,
onCommit: {
print("someText = \(someText)")
self.amount = Double(someText)!
}
)
.onChange(of: someText, perform: { value in
if someText != oldText {
someText = editInputNumber(textIn: someText)
oldText = someText
}
}
)
Text("The amount entered was \(self.amount)")
}
}
}
使用 onChange 我 运行 解决了以编程方式更改绑定字段第二次触发 onChange 的问题。这是 Kludge 的最大部分,我必须在其中测试对 onChange 的第二次调用。
然后是我创建的函数来响应用户的输入。
此函数从视图中调用,它接收字符串并首先调用一个函数将其过滤为仅数字。消除意外输入的任何非数字
它获取结果并将其提交给格式化函数并取回格式化的字符串。
func editInputNumber(textIn: String) -> String
{
var fixedText = ""
var charactersWork = [Character]()
charactersWork = getNumericInputString(textIn: textIn)
fixedText = formatDecimalNumericString(charactersWork:
charactersWork)
return fixedText
}
将输入字符串过滤为仅数字的功能。它也过滤掉先前条目中的任何前导零。
func getNumericInputString(textIn: String) -> [Character]
{
var leadingZero = true
let charactersIn = Array(textIn)
var charactersOut = [Character]()
for i in 0..<charactersIn.count {
if charactersIn[i].isNumber {
if let number = Int(String(charactersIn[i]))
{
if number > 0
{
leadingZero = false
}
}
if !leadingZero {
charactersOut.append(charactersIn[i])
}
}
}
return charactersOut
}
在将字符串过滤为仅包含数字的字符数组后,此函数会对其进行格式化以便输出回视图。如果它是输入的前两个数字,函数会在值上设置前导零。
func formatDecimalNumericString(charactersWork: [Character]) -
> String
{
let number: String = "000"
var charactersOut = [Character]()
if charactersWork.count < 3
{
charactersOut = Array(number)
}
if charactersWork.count > 0
{
if charactersWork.count == 1
{
charactersOut[2] = charactersWork[0]
}
if charactersWork.count == 2
{
charactersOut[1] = charactersWork[0]
charactersOut[2] = charactersWork[1]
}
if charactersWork.count > 2
{
for i in 0..<charactersWork.count
{
charactersOut.append(charactersWork[i])
}
}
charactersOut.insert(".", at: (charactersOut.count - 2))
}
return String(charactersOut)
}
我运行进入同样的问题!使用已接受的答案作为灵感(感谢您的发帖!)我能够想出一个更少 kludgy
的解决方案。
import SwiftUI
struct Example: View {
@Binding var valueText: String
var body: some View {
TextField("Enter Value", text: $valueText)
.onChange(of: valueText, perform: { newValue in
valueText = editOnTheFly(input: newValue, leadingZeros: 0, decimalPlaces: 2)
})
}
func editOnTheFly(input: String, leadingZeros: Int, decimalPlaces: Int) -> String {
// Strip all non-numeric characters from the String
var result = input.replacingOccurrences(of: "[^0123456789]", with: "", options: .regularExpression)
// If the String can't be cast as a Double return ""
guard let resultAsDouble = Double(result) else {
return ""
}
let formatter = NumberFormatter()
formatter.minimumIntegerDigits = leadingZeros
formatter.minimumFractionDigits = decimalPlaces
formatter.maximumFractionDigits = decimalPlaces
// If `2` decimalPlaces past in, the divider would be 100.0
let dividerDecimal = pow(10.0, decimalPlaces)
let dividerDouble = NSDecimalNumber(decimal: dividerDecimal).doubleValue
// Turns an input of `42` into `0.42`
result = formatter.string(from: NSNumber(value: resultAsDouble/dividerDouble)) ?? ""
return result
}
}
我希望能够在用户逐字符键入时编辑文本字段。我希望能够获取一个数字字段并在用户输入时输入:
- 过滤掉非数字字符并return仅返回已输入的有效字符。
- 格式化数字,以便在用户输入时得到相反的数字。即 120.36 将显示为: 0.01 0.12 1.20 12.03 120.36
如果用户输入了无效字符,则 return 不包含无效字符的字符串。 我对如何捕获 TextField、编辑它以及 return 它的格式如我所展示的感到困惑。
我已经走到这一步了:(不远了:-) 我已经在 Whosebug 上尝试了很多解决方案,但 none 似乎让我到达了我想去的地方.. onEditChange 变化时 等等
构造 SwiftUIView:视图 {
@State var amount: String = "0.00"
var body: some View {
TextField(
"Enter amount here ",
text: $amount
)
}
}
我怀疑我的要求太宽泛了,可能有点要求为我做程序的味道。事实并非如此,但也许我可以再缩小范围。
无论如何,我能够达到我想要的结果。我认为这是一个巨大的 KLUDGE,但这是我所能想到的。
首先是我的 SwiftUI 视图:
struct SwiftUIView: View {
@State var someText: String = "0.00"
@State var oldText: String = ""
@State var amount: Double = 0.00
var body: some View {
VStack {
TextField("Enter some text here", text: $someText,
onCommit: {
print("someText = \(someText)")
self.amount = Double(someText)!
}
)
.onChange(of: someText, perform: { value in
if someText != oldText {
someText = editInputNumber(textIn: someText)
oldText = someText
}
}
)
Text("The amount entered was \(self.amount)")
}
}
}
使用 onChange 我 运行 解决了以编程方式更改绑定字段第二次触发 onChange 的问题。这是 Kludge 的最大部分,我必须在其中测试对 onChange 的第二次调用。
然后是我创建的函数来响应用户的输入。 此函数从视图中调用,它接收字符串并首先调用一个函数将其过滤为仅数字。消除意外输入的任何非数字
它获取结果并将其提交给格式化函数并取回格式化的字符串。
func editInputNumber(textIn: String) -> String
{
var fixedText = ""
var charactersWork = [Character]()
charactersWork = getNumericInputString(textIn: textIn)
fixedText = formatDecimalNumericString(charactersWork:
charactersWork)
return fixedText
}
将输入字符串过滤为仅数字的功能。它也过滤掉先前条目中的任何前导零。
func getNumericInputString(textIn: String) -> [Character]
{
var leadingZero = true
let charactersIn = Array(textIn)
var charactersOut = [Character]()
for i in 0..<charactersIn.count {
if charactersIn[i].isNumber {
if let number = Int(String(charactersIn[i]))
{
if number > 0
{
leadingZero = false
}
}
if !leadingZero {
charactersOut.append(charactersIn[i])
}
}
}
return charactersOut
}
在将字符串过滤为仅包含数字的字符数组后,此函数会对其进行格式化以便输出回视图。如果它是输入的前两个数字,函数会在值上设置前导零。
func formatDecimalNumericString(charactersWork: [Character]) -
> String
{
let number: String = "000"
var charactersOut = [Character]()
if charactersWork.count < 3
{
charactersOut = Array(number)
}
if charactersWork.count > 0
{
if charactersWork.count == 1
{
charactersOut[2] = charactersWork[0]
}
if charactersWork.count == 2
{
charactersOut[1] = charactersWork[0]
charactersOut[2] = charactersWork[1]
}
if charactersWork.count > 2
{
for i in 0..<charactersWork.count
{
charactersOut.append(charactersWork[i])
}
}
charactersOut.insert(".", at: (charactersOut.count - 2))
}
return String(charactersOut)
}
我运行进入同样的问题!使用已接受的答案作为灵感(感谢您的发帖!)我能够想出一个更少 kludgy
的解决方案。
import SwiftUI
struct Example: View {
@Binding var valueText: String
var body: some View {
TextField("Enter Value", text: $valueText)
.onChange(of: valueText, perform: { newValue in
valueText = editOnTheFly(input: newValue, leadingZeros: 0, decimalPlaces: 2)
})
}
func editOnTheFly(input: String, leadingZeros: Int, decimalPlaces: Int) -> String {
// Strip all non-numeric characters from the String
var result = input.replacingOccurrences(of: "[^0123456789]", with: "", options: .regularExpression)
// If the String can't be cast as a Double return ""
guard let resultAsDouble = Double(result) else {
return ""
}
let formatter = NumberFormatter()
formatter.minimumIntegerDigits = leadingZeros
formatter.minimumFractionDigits = decimalPlaces
formatter.maximumFractionDigits = decimalPlaces
// If `2` decimalPlaces past in, the divider would be 100.0
let dividerDecimal = pow(10.0, decimalPlaces)
let dividerDouble = NSDecimalNumber(decimal: dividerDecimal).doubleValue
// Turns an input of `42` into `0.42`
result = formatter.string(from: NSNumber(value: resultAsDouble/dividerDouble)) ?? ""
return result
}
}