在UITextField中的安全文本上添加自定义视图,并能够将其删除

时间:2017-07-22 04:15:11

标签: ios swift uitextfield

我正在使用一个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();
        }
    }

1 个答案:

答案 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()
  }
}