我正在使用一个4位数针的登录屏幕。我有四个不同的文本字段来取引脚输入。我试图通过显示一些星形图标来显示用户输入的数字。当用户输入数字时,我通过在UITextView中添加一个subView呈现星形。
我可以输入所有四位数字。现在我想添加一个按退格键的功能,以便删除先前输入的数字。我找不到办法做到这一点。任何人都可以帮助我。
某些堆栈溢出解决方案建议检查shouldCheckCharactersInRange中的字符串。但是要检测退格,您需要从函数返回true。如果我们这样做,那么星形将与按下的数字一起显示。
import UIKit
class PinSetupViewController: UIViewController, UITextFieldDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setupNavbar()
setupViews();
view.backgroundColor = UIColor(red: 239/255, green: 239/255, blue: 239/255, alpha: 1);
firstPinTextView.delegate = self;
secondPinTextView.delegate = self;
thirdPinTextView.delegate = self;
fourthPinTextView.delegate = self;
}
enum pinLabelFrame: Int {
case height = 54, width = 50;
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
}
switch textField {
case firstPinTextView:
let star = Star(frame: CGRect(x: 0, y: 0, width: pinLabelFrame.width.rawValue, height: pinLabelFrame.height.rawValue))
firstPinTextView.addSubview(star);
secondPinTextView.becomeFirstResponder();
break;
case secondPinTextView:
let star = Star(frame: CGRect(x: 0, y: 0, width: pinLabelFrame.width.rawValue, height: pinLabelFrame.height.rawValue))
secondPinTextView.addSubview(star);
thirdPinTextView.becomeFirstResponder();
break;
case thirdPinTextView:
let star = Star(frame: CGRect(x: 0, y: 0, width: pinLabelFrame.width.rawValue, height: pinLabelFrame.height.rawValue))
thirdPinTextView.addSubview(star);
fourthPinTextView.becomeFirstResponder();
case fourthPinTextView:
let star = Star(frame: CGRect(x: 0, y: 0, width: pinLabelFrame.width.rawValue, height: pinLabelFrame.height.rawValue))
fourthPinTextView.addSubview(star);
thirdPinTextView.resignFirstResponder();
default:
break;
}
return true;
}
func setupNavbar(){
navigationItem.title = "Set a PIN" // set title of navigation bar
navigationController?.navigationBar.titleTextAttributes = [NSAttributedStringKey.font.rawValue: UIFont.systemFont(ofSize: 16, weight: UIFont.Weight.regular)]; //Change the font from bold to normal
navigationController?.navigationBar.barTintColor = .white; //set navigation bar background color to white
navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(named: "back"), style: .done, target: self, action: nil);
navigationItem.leftBarButtonItem?.tintColor = .black;
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Skip", style: .plain, target: self, action: #selector(showConfirmPIN));
}
@objc func showConfirmPIN(){
topTextView.text = "Confirm PIN."
self.dismiss(animated: false) {
self.present(UINavigationController(rootViewController: PinSetupViewController()), animated: false, completion: nil);
}
}
func setupViews(){
view.addSubview(topView);
view.addSubview(topTextView);
view.addSubview(pinContainerView);
view.addSubview(bottomTextView);
topView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true;
topView.topAnchor.constraint(equalTo: view.topAnchor, constant: 60).isActive = true;
topView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true;
topView.heightAnchor.constraint(equalToConstant: 10).isActive = true;
topTextView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true;
topTextView.topAnchor.constraint(equalTo: topView.bottomAnchor, constant: 10).isActive = true;
topTextView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true;
topTextView.heightAnchor.constraint(equalToConstant: 50).isActive = true;
pinContainerView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true;
pinContainerView.topAnchor.constraint(equalTo: topTextView.bottomAnchor, constant: 10).isActive = true;
pinContainerView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.6).isActive = true;
pinContainerView.heightAnchor.constraint(equalToConstant: 54).isActive = true;
setupPinsView();
bottomTextView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true;
bottomTextView.topAnchor.constraint(equalTo: pinContainerView.bottomAnchor, constant: 10).isActive = true;
bottomTextView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true;
bottomTextView.heightAnchor.constraint(equalToConstant: 130).isActive = true;
}
func setupPinsView(){
pinContainerView.addSubview(firstPinTextView);
pinContainerView.addSubview(secondPinTextView);
pinContainerView.addSubview(thirdPinTextView);
pinContainerView.addSubview(fourthPinTextView);
firstPinTextView.leftAnchor.constraint(equalTo: pinContainerView.leftAnchor).isActive = true;
firstPinTextView.topAnchor.constraint(equalTo: pinContainerView.topAnchor).isActive = true;
firstPinTextView.bottomAnchor.constraint(equalTo: pinContainerView.bottomAnchor).isActive = true;
firstPinTextView.widthAnchor.constraint(equalToConstant: 50).isActive = true;
secondPinTextView.leftAnchor.constraint(equalTo: firstPinTextView.rightAnchor, constant: 20).isActive = true;
secondPinTextView.topAnchor.constraint(equalTo: pinContainerView.topAnchor).isActive = true;
secondPinTextView.bottomAnchor.constraint(equalTo: pinContainerView.bottomAnchor).isActive = true;
secondPinTextView.widthAnchor.constraint(equalToConstant: 50).isActive = true;
thirdPinTextView.leftAnchor.constraint(equalTo: secondPinTextView.rightAnchor, constant: 20).isActive = true;
thirdPinTextView.topAnchor.constraint(equalTo: pinContainerView.topAnchor).isActive = true;
thirdPinTextView.bottomAnchor.constraint(equalTo: pinContainerView.bottomAnchor).isActive = true;
thirdPinTextView.widthAnchor.constraint(equalToConstant: 50).isActive = true;
fourthPinTextView.leftAnchor.constraint(equalTo: thirdPinTextView.rightAnchor, constant: 20).isActive = true;
fourthPinTextView.topAnchor.constraint(equalTo: pinContainerView.topAnchor).isActive = true;
fourthPinTextView.bottomAnchor.constraint(equalTo: pinContainerView.bottomAnchor).isActive = true;
fourthPinTextView.widthAnchor.constraint(equalToConstant: 50).isActive = true;
}
let topView : UIView = {
let view = UIView();
view.backgroundColor = UIColor.black;
view.translatesAutoresizingMaskIntoConstraints = false;
return view;
}();
let pinContainerView : UIView = {
let view = UIView();
view.backgroundColor = UIColor.clear;
view.translatesAutoresizingMaskIntoConstraints = false;
return view;
}();
let topTextView: UITextView = {
let tv = UITextView();
tv.textAlignment = .center
tv.text = "Set a PIN for quicker mobile \n banking access.";
tv.font = UIFont.boldSystemFont(ofSize: 14);
tv.backgroundColor = .clear;
tv.isEditable = false;
tv.isSelectable = false;
tv.translatesAutoresizingMaskIntoConstraints = false;
return tv;
}();
let firstPinTextView : UITextField = {
let tf = UITextField();
tf.backgroundColor = .black;
tf.keyboardType = .numberPad;
tf.textAlignment = .center;
tf.textColor = UIColor.white;
tf.tintColor = .clear;
tf.font = UIFont.systemFont(ofSize: 40);
tf.becomeFirstResponder();
tf.layer.cornerRadius = 5;
tf.translatesAutoresizingMaskIntoConstraints = false;
return tf;
}();
let secondPinTextView : UITextField = {
let tf = UITextField();
tf.backgroundColor = .black;
tf.keyboardType = .numberPad;
tf.textAlignment = .center;
tf.textColor = UIColor.white;
tf.tintColor = .clear;
tf.font = UIFont.systemFont(ofSize: 18);
tf.layer.cornerRadius = 5;
tf.translatesAutoresizingMaskIntoConstraints = false;
return tf;
}();
let thirdPinTextView : UITextField = {
let tf = UITextField();
tf.backgroundColor = .black;
tf.keyboardType = .numberPad;
tf.textAlignment = .center;
tf.textColor = UIColor.white;
tf.tintColor = .clear;
tf.font = UIFont.systemFont(ofSize: 18);
tf.layer.cornerRadius = 5;
tf.translatesAutoresizingMaskIntoConstraints = false;
return tf;
}();
let fourthPinTextView : UITextField = {
let tf = UITextField();
tf.backgroundColor = .black;
tf.keyboardType = .numberPad;
tf.textAlignment = .center;
tf.textColor = UIColor.white;
tf.tintColor = .clear;
tf.font = UIFont.systemFont(ofSize: 18);
tf.layer.cornerRadius = 5;
tf.translatesAutoresizingMaskIntoConstraints = false;
return tf;
}();
let bottomTextView: UITextView = {
let tv = UITextView();
let attributedText = NSAttributedString(string: "If you'd prefer to use your NetBank password to log \n on instead of a PIN, simply skip this step. \n\n Don't choose a PIN that can be easily guessed (e.g. \n you birthday or name). If you do, you may liable \n for unauthorized transactions. \n\n This PIN will apply wherever you access mobile \n banking (excluding CommSec and CommBiz apps). ", attributes: [NSAttributedStringKey.font : UIFont.systemFont(ofSize: 11)]);
tv.attributedText = attributedText;
tv.textAlignment = .center
tv.backgroundColor = UIColor.clear;
tv.keyboardAppearance = UIKeyboardAppearance.dark;
tv.isEditable = false;
tv.isSelectable = false;
tv.translatesAutoresizingMaskIntoConstraints = false;
return tv;
}();
}
// -----------------回答--------------------- //
//Add this function to your text field target
@objc func showSecurePassword(_ textField: UITextField){
guard let char = textField.text?.cString(using: String.Encoding.utf8) else{
return
}
let isBackSpace = strcmp(char, "\\b")
pins.newPin += textField.text!
switch textField{
case firstPinTextField:
if !(isBackSpace == -92){
//Valid digit entered i.e 0 - 9
addViewToTextField(firstPinTextField, secureView.star1);
}else{
//Backspace detected ...
removerSubviewFromTextField(secureView.star1);
pins.newPin = String(pins.newPin.dropLast()) //Remove the last element from the 4 digit pin
firstPinTextField.becomeFirstResponder();
}
case secondPinTextField:
if !(isBackSpace == -92){
addViewToTextField(secondPinTextField, secureView.star2);
}else{
removerSubviewFromTextField(secureView.star2);
pins.newPin = String(pins.newPin.dropLast()) //Remove the last element from the 4 digit pin
firstPinTextField.becomeFirstResponder();
}
case thirdPinTextField:
if !(isBackSpace == -92){
addViewToTextField(thirdPinTextField, secureView.star3);
}else{
removerSubviewFromTextField(secureView.star3);
pins.newPin = String(pins.newPin.dropLast()) //Remove the last element from the 4 digit pin
secondPinTextField.becomeFirstResponder();
}
case fourthPinTextField:
if !(isBackSpace == -92){
addViewToTextField(fourthPinTextField, secureView.star4);
if((!pins.oldPin.isEmpty) && (pins.oldPin == pins.newPin)){
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
self.resetAllTextFields();
self.removeAllSubViewsFromTextField();
self.showTermsAndConditionViewController();
})
}else if ((!pins.newPin.isEmpty && !pins.oldPin.isEmpty) && pins.oldPin != pins.newPin){
pins.newPin = ""; //Reset both pins
pins.oldPin = "";
resetAllTextFields(); //Resest all text fields
removeAllSubViewsFromTextField() //Remove all the views from text Fields
vibratePhone(); //Vibrate phone
}
else{
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
self.promtForReenteringPassword();
})
}
}else{
removerSubviewFromTextField(secureView.star4);
pins.newPin = String(pins.newPin.dropLast()) //Remove the last element from the 4 digit pin
thirdPinTextField.becomeFirstResponder();
}
default:
break;
}
print("Old pin is \(pins.oldPin)");
print("New pin is \(pins.newPin)");
}
// Function to limit the number of characters in a text field so that the focus remains within itself when first character is entered and goes to other text field when more than one character gets entered
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
switch textField {
case firstPinTextField:
if !isNumberOfCharsWithinDefinedValue(firstPinTextField, string: string){
firstPinTextField.text = getTextToSetTheTextField(firstPinTextField, string: string)
secondPinTextField.becomeFirstResponder();
}
case secondPinTextField:
if !isNumberOfCharsWithinDefinedValue(secondPinTextField, string: string){
secondPinTextField.text = getTextToSetTheTextField(secondPinTextField, string: string)
thirdPinTextField.becomeFirstResponder();
}
case thirdPinTextField:
if !isNumberOfCharsWithinDefinedValue(thirdPinTextField, string: string){
thirdPinTextField.text = getTextToSetTheTextField(thirdPinTextField, string: string)
fourthPinTextField.becomeFirstResponder();
}
case fourthPinTextField:
if !isNumberOfCharsWithinDefinedValue(fourthPinTextField, string: string){
fourthPinTextField.text = getTextToSetTheTextField(fourthPinTextField, string: string)
return false
}
default:
break
}
return true;
}
//Check number of characters within the given text field. If number of characters exceeds the limit then return false else return true;
func isNumberOfCharsWithinDefinedValue(_ textField: UITextField, string: String) -> Bool{
if let text = textField.text {
let str = text + string;
if str.count <= constant.TEXT_FIELD_MAX_CHAR{
return true
}
}
return false;
}
func removerSubviewFromTextField(_ textView: UIView){
if let tv = textView.viewWithTag(100){
tv.removeFromSuperview();
}
}
答案 0 :(得分:1)
将此内容写入textField委托函数:
if string.characters.count == 0 && range.length > 0 {
// Back pressed
switch textField {
case secondPinTextView:
clearTextView(firstPinTextView);
firstPinTextView.becomeFirstResponder();
break;
case thirdPinTextView:
clearTextView(secondPinTextView);
secondPinTextView.becomeFirstResponder();
break;
case fourthPinTextView:
clearTextView(thirdPinTextView);
thirdPinTextView.becomeFirstResponder();
break;
default:
break;
}
将此属性添加到星标定义中:
testView.tag = 100
创建此功能:
func clearTextView(textView: UITextView){
if let viewWithTag = textView.viewWithTag(100) {
textView.text = "";
viewWithTag.removeFromSuperview()
}
}