清除按钮按下swiftui时如何自动上一个文本字段
How to automatically previous textfield when clear button press swiftui
我正在尝试创建 OTP 屏幕,当用户在第一个文本字段中输入数字并且光标自动移动到下一个文本字段后,我得到了它的功能,但是当用户删除文本时我被卡住了在当前文本字段中以及如何自动移动到上一个文本字段。
截图:-
代码:-
import SwiftUI
struct VerficationCode: View {
@State private var numberOfCells: Int = 6
@State private var currentlySelectedCell = 0
var body: some View {
HStack {
Group {
ForEach(0 ..< self.numberOfCells) { index in
CharacterInputCell(currentlySelectedCell: self.$currentlySelectedCell, index: index)
}
}.frame(width:15,height: 56)
.padding(.horizontal)
.foregroundColor(.white)
.cornerRadius(10)
.keyboardType(.numberPad)
}
}
}
struct CharacterInputCell: View {
@State private var textValue: String = ""
@Binding var currentlySelectedCell: Int
var index: Int
var responder: Bool {
return index == currentlySelectedCell
}
var body: some View {
CustomTextField(text: $textValue, currentlySelectedCell: $currentlySelectedCell, isFirstResponder: responder)
}
}
struct CustomTextField: UIViewRepresentable {
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
@Binding var currentlySelectedCell: Int
var didBecomeFirstResponder = false
init(text: Binding<String>, currentlySelectedCell: Binding<Int>) {
_text = text
_currentlySelectedCell = currentlySelectedCell
}
func textFieldDidChangeSelection(_ textField: UITextField) {
DispatchQueue.main.async {
self.text = textField.text ?? ""
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentText = textField.text ?? ""
guard let stringRange = Range(range, in: currentText) else { return false }
let updatedText = currentText.replacingCharacters(in: stringRange, with: string)
if updatedText.count <= 1 {
self.currentlySelectedCell += 1
}
return updatedText.count <= 1
}
}
@Binding var text: String
@Binding var currentlySelectedCell: Int
var isFirstResponder: Bool = false
func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
textField.textAlignment = .center
textField.keyboardType = .decimalPad
return textField
}
func makeCoordinator() -> CustomTextField.Coordinator {
return Coordinator(text: $text, currentlySelectedCell: $currentlySelectedCell)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
uiView.text = text
if isFirstResponder && !context.coordinator.didBecomeFirstResponder {
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
}
谁能告诉我点击清除按钮时如何自动返回,我已经尝试实现但还没有结果。
如有任何帮助,我们将不胜感激。
提前致谢。
试一试
import SwiftUI
public struct PasscodeField: View {
var maxDigits: Int = 6
var label = "Enter One Time Password"
@State var pin: String = ""
@State var showPin = true
//@State var isDisabled = false
var handler: (String, (Bool) -> Void) -> Void
public var body: some View {
VStack{
Text(label).font(.title)
ZStack {
pinDots
backgroundField
}
showPinStack
}
}
private var pinDots: some View {
HStack {
Spacer()
ForEach(0..<maxDigits) { index in
Image(systemName: self.getImageName(at: index))
.font(.system(size: 60))
Spacer()
}.frame(minWidth: 0, maxWidth: .infinity)
.padding(.trailing, -24)
}
}
private var backgroundField: some View {
let boundPin = Binding<String>(get: { self.pin }, set: { newValue in
self.pin = newValue
self.submitPin()
})
return TextField("", text: boundPin, onCommit: submitPin)
// Introspect library can used to make the textField become first resonder on appearing
// if you decide to add the pod 'Introspect' and import it, comment #50 to #53 and uncomment #55 to #61
.accentColor(.clear)
.foregroundColor(.clear)
.keyboardType(.numberPad)
//.disabled(isDisabled)
// .introspectTextField { textField in
// textField.tintColor = .clear
// textField.textColor = .clear
// textField.keyboardType = .numberPad
// textField.becomeFirstResponder()
// textField.isEnabled = !self.isDisabled
// }
}
private var showPinStack: some View {
HStack {
Spacer()
if !pin.isEmpty {
showPinButton
}
}
.frame(height: 100)
.padding([.trailing])
}
private var showPinButton: some View {
Button(action: {
self.showPin.toggle()
}, label: {
self.showPin ?
Image(systemName: "eye.slash.fill").foregroundColor(.primary) :
Image(systemName: "eye.fill").foregroundColor(.primary)
})
}
private func submitPin() {
//guard !pin.isEmpty else {
//showPin = false
//return
//}
if pin.count == maxDigits {
//isDisabled = true
handler(pin) { isSuccess in
if isSuccess {
print("pin matched, go to next page, no action to perfrom here")
} else {
pin = ""
//isDisabled = false
print("this has to called after showing toast why is the failure")
}
}
}
// this code is never reached under normal circumstances. If the user pastes a text with count higher than the
// max digits, we remove the additional characters and make a recursive call.
if pin.count > maxDigits {
pin = String(pin.prefix(maxDigits))
submitPin()
}
}
private func getImageName(at index: Int) -> String {
if index >= self.pin.count {
return "circle"
}
if self.showPin {
return self.pin.digits[index].numberString + ".circle"
}
return "circle.fill"
}
}
extension String {
var digits: [Int] {
var result = [Int]()
for char in self {
if let number = Int(String(char)) {
result.append(number)
}
}
return result
}
}
extension Int {
var numberString: String {
guard self < 10 else { return "0" }
return String(self)
}
}
我正在尝试创建 OTP 屏幕,当用户在第一个文本字段中输入数字并且光标自动移动到下一个文本字段后,我得到了它的功能,但是当用户删除文本时我被卡住了在当前文本字段中以及如何自动移动到上一个文本字段。
截图:-
代码:-
import SwiftUI
struct VerficationCode: View {
@State private var numberOfCells: Int = 6
@State private var currentlySelectedCell = 0
var body: some View {
HStack {
Group {
ForEach(0 ..< self.numberOfCells) { index in
CharacterInputCell(currentlySelectedCell: self.$currentlySelectedCell, index: index)
}
}.frame(width:15,height: 56)
.padding(.horizontal)
.foregroundColor(.white)
.cornerRadius(10)
.keyboardType(.numberPad)
}
}
}
struct CharacterInputCell: View {
@State private var textValue: String = ""
@Binding var currentlySelectedCell: Int
var index: Int
var responder: Bool {
return index == currentlySelectedCell
}
var body: some View {
CustomTextField(text: $textValue, currentlySelectedCell: $currentlySelectedCell, isFirstResponder: responder)
}
}
struct CustomTextField: UIViewRepresentable {
class Coordinator: NSObject, UITextFieldDelegate {
@Binding var text: String
@Binding var currentlySelectedCell: Int
var didBecomeFirstResponder = false
init(text: Binding<String>, currentlySelectedCell: Binding<Int>) {
_text = text
_currentlySelectedCell = currentlySelectedCell
}
func textFieldDidChangeSelection(_ textField: UITextField) {
DispatchQueue.main.async {
self.text = textField.text ?? ""
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let currentText = textField.text ?? ""
guard let stringRange = Range(range, in: currentText) else { return false }
let updatedText = currentText.replacingCharacters(in: stringRange, with: string)
if updatedText.count <= 1 {
self.currentlySelectedCell += 1
}
return updatedText.count <= 1
}
}
@Binding var text: String
@Binding var currentlySelectedCell: Int
var isFirstResponder: Bool = false
func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> UITextField {
let textField = UITextField(frame: .zero)
textField.delegate = context.coordinator
textField.textAlignment = .center
textField.keyboardType = .decimalPad
return textField
}
func makeCoordinator() -> CustomTextField.Coordinator {
return Coordinator(text: $text, currentlySelectedCell: $currentlySelectedCell)
}
func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<CustomTextField>) {
uiView.text = text
if isFirstResponder && !context.coordinator.didBecomeFirstResponder {
uiView.becomeFirstResponder()
context.coordinator.didBecomeFirstResponder = true
}
}
}
谁能告诉我点击清除按钮时如何自动返回,我已经尝试实现但还没有结果。
如有任何帮助,我们将不胜感激。
提前致谢。
试一试
import SwiftUI
public struct PasscodeField: View {
var maxDigits: Int = 6
var label = "Enter One Time Password"
@State var pin: String = ""
@State var showPin = true
//@State var isDisabled = false
var handler: (String, (Bool) -> Void) -> Void
public var body: some View {
VStack{
Text(label).font(.title)
ZStack {
pinDots
backgroundField
}
showPinStack
}
}
private var pinDots: some View {
HStack {
Spacer()
ForEach(0..<maxDigits) { index in
Image(systemName: self.getImageName(at: index))
.font(.system(size: 60))
Spacer()
}.frame(minWidth: 0, maxWidth: .infinity)
.padding(.trailing, -24)
}
}
private var backgroundField: some View {
let boundPin = Binding<String>(get: { self.pin }, set: { newValue in
self.pin = newValue
self.submitPin()
})
return TextField("", text: boundPin, onCommit: submitPin)
// Introspect library can used to make the textField become first resonder on appearing
// if you decide to add the pod 'Introspect' and import it, comment #50 to #53 and uncomment #55 to #61
.accentColor(.clear)
.foregroundColor(.clear)
.keyboardType(.numberPad)
//.disabled(isDisabled)
// .introspectTextField { textField in
// textField.tintColor = .clear
// textField.textColor = .clear
// textField.keyboardType = .numberPad
// textField.becomeFirstResponder()
// textField.isEnabled = !self.isDisabled
// }
}
private var showPinStack: some View {
HStack {
Spacer()
if !pin.isEmpty {
showPinButton
}
}
.frame(height: 100)
.padding([.trailing])
}
private var showPinButton: some View {
Button(action: {
self.showPin.toggle()
}, label: {
self.showPin ?
Image(systemName: "eye.slash.fill").foregroundColor(.primary) :
Image(systemName: "eye.fill").foregroundColor(.primary)
})
}
private func submitPin() {
//guard !pin.isEmpty else {
//showPin = false
//return
//}
if pin.count == maxDigits {
//isDisabled = true
handler(pin) { isSuccess in
if isSuccess {
print("pin matched, go to next page, no action to perfrom here")
} else {
pin = ""
//isDisabled = false
print("this has to called after showing toast why is the failure")
}
}
}
// this code is never reached under normal circumstances. If the user pastes a text with count higher than the
// max digits, we remove the additional characters and make a recursive call.
if pin.count > maxDigits {
pin = String(pin.prefix(maxDigits))
submitPin()
}
}
private func getImageName(at index: Int) -> String {
if index >= self.pin.count {
return "circle"
}
if self.showPin {
return self.pin.digits[index].numberString + ".circle"
}
return "circle.fill"
}
}
extension String {
var digits: [Int] {
var result = [Int]()
for char in self {
if let number = Int(String(char)) {
result.append(number)
}
}
return result
}
}
extension Int {
var numberString: String {
guard self < 10 else { return "0" }
return String(self)
}
}