skip to Main Content

I have a sign in screen in which two fields are there password and email textfield.
I added both textfield with stackview. After adding textfields, I need to add button of password lock. After clicking on password lock button user can see the password. I took button from library and try to add on textfield but, due to stackview it always set as third element for stackview. So I am unable to add.
So I decided to add with extension of textfield. So i added button successfully in utility class,
but unable to add action with selector. It showing an error

Value of type ‘UIViewController’ has no member ‘passwordAction’

My code for add button is

extension UITextField {

func passwordButton(vc:UIViewController){
    let paddingView = UIView(frame: CGRect(x: 25, y: 25, width: 24, height: 17))
    let passwordButton = UIButton(frame: CGRect(x: 0, y: 0, width: 24, height: 17))
    passwordButton.setImage(UIImage(named: "show_password"), for: .normal)
    passwordButton.addTarget(vc, action: #selector(vc.passwordAction), for: .touchUpInside)
    paddingView.addSubview(passwordButton)
    self.addSubview(paddingView)
}
}
class Loginviewcontroller{
   passwordTextField.passwordButton(vc: self)
 func passwordAction(){
  print("action")
 }
 }

I am calling this method from login controller.

So I have two question:-

  1. when two textfield are attached with stackview, we can not put button on textfield with storyboard?
  2. How can I make globle method to add button and add action that can access in uiviewcontroller?

2

Answers


  1. Error is self explanatory, you added the passwordAction method to Loginviewcontroller but in func passwordButton you take a UIViewController as an argument. As a result even when you pass instance of Loginviewcontroller to passwordButton function call, in the function scope vc is just another UIViewController and clearly all UIViewControllers does not have a method named passwordAction.

    As you said you wanna make global method to add button and add action that can access in uiviewcontroller you can follow below approach

    Step 1: Declare a protocol

    @objc protocol SecureTextProtocol where Self: UIViewController {
        func passwordAction()
    }
    

    Step 2: Update your passwordButton method to take SecureTextProtocol instead of plain UIViewController

    extension UITextField {
    
        func passwordButton(vc:SecureTextProtocol){
            let paddingView = UIView(frame: CGRect(x: 25, y: 25, width: 24, height: 17))
            let passwordButton = UIButton(frame: CGRect(x: 0, y: 0, width: 24, height: 17))
            passwordButton.setImage(UIImage(named: "show_password"), for: .normal)
            passwordButton.addTarget(vc, action: #selector(vc.passwordAction), for: .touchUpInside)
            paddingView.addSubview(passwordButton)
            self.addSubview(paddingView)
        }
    }
    

    Step 3: Make your ViewController’s that want to get the button action to confirm to SecureTextProtocol protocol

    class Loginviewcontroller: UIViewController, SecureTextProtocol {
        passwordTextField.passwordButton(vc: self)
    
        func passwordAction(){
            print("action")
        }
    }
    

    That should do the job

    Login or Signup to reply.
  2. You can always solve this problem with simple code, that’s the way I do it.

        extension UITextField {
    func setPasswordToggleImage(_ button: UIButton) {
        if(isSecureTextEntry){
            button.setImage(UIImage(named: "ic_password_visible"), for: .normal)
        }else{
            button.setImage(UIImage(named: "ic_password_invisible"), for: .normal)
    
        }
    }
    
    func enablePasswordToggle(){
        let button = UIButton(type: .custom)
        setPasswordToggleImage(button)
        button.imageEdgeInsets = UIEdgeInsets(top: 0, left: -16, bottom: 0, right: 0)
        button.frame = CGRect(x: CGFloat(self.frame.size.width - 25), y: CGFloat(5), width: CGFloat(25), height: CGFloat(25))
        button.addTarget(self, action: #selector(self.togglePasswordView), for: .touchUpInside)
        self.rightView = button
        self.rightViewMode = .always
    }
    @objc func togglePasswordView(_ sender: Any) {
        self.isSecureTextEntry = !self.isSecureTextEntry
        setPasswordToggleImage(sender as! UIButton)
    }
    }
    

    then on viewcontroller’s viewdidload just call the functions on your storyboards

    override func viewDidLoad() {
                 super.viewDidLoad()
                 txtPassword.enablePasswordToggle()
                 txtConfirmPassword.enablePasswordToggle()
             }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search