Calling delegate methods in custom UITextField class - ios

So this might be basic Swift knowledge but I'm struggling to find this info anywhere online. I'm trying to create a custom text field glass with global styles that utilizes UITextFieldDelegate methods. In particular I'm trying to use the function textFieldDidBeginEditing(). In my example below I'm just trying to print "hello" when a text field is being edited, however nothing is being printed to the console when I begin typing in my custom text field.
If I'm doing anything incorrectly please let me know, as I don't work with Swift too much. Thank you!
class LoFMTextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
styleTextField()
}
required init?(coder LoFMDecoder: NSCoder) {
super.init(coder: LoFMDecoder)
styleTextField()
}
func styleTextField() {
layer.cornerRadius = 5.0
layer.borderWidth = 1.0
layer.borderColor = UIColor.white.cgColor
backgroundColor = UIColor.white
}
}
extension UITextFieldDelegate {
func textFieldDidBeginEditing(textField: UITextField!) {
print("hello")
}
}

Add this line inside styleTextField
self.delegate = self
Then
extension LoFMTextField : UITextFieldDelegate {
func textFieldDidBeginEditing(_ textField: UITextField) {
print("hello")
}
}
Note: it's (_ textField: UITextField) not (textField: UITextField!)

Related

Using #objc delegate methods with multiple arguments

I want to be able to pass multiple arguments to a #selector() method other than only the sender itself.
Say, I have a UITextField which has a UITapGestureRecognizer, and I want some other class to be the delegate of this UITapGestureRecognizer. I write a delegate protocol for it called SomeDelegateProcotol. However, I also want to pass the instance of the UITextField to the delegate upon tap. I figured things might look something like this:
// The delegate
class Delegate: SomeDelegateProcotol {
private let textField = TextField()
func handleTapFromView(_ sender: UITapGestureRecognizer, textField: UITextField) {
print("Hey! I should handle the tap from the user.")
}
init() {
textField.delegate = self
}
}
// The protocol
#objc protocol SomeDelegateProtocol {
#objc func handletapFromView(_ sender: UITapGestureRecognizer, textField: UITextField)
}
class TextField: UITextField {
weak var delegate: SomeDelegateProtocol?
override init(frame: CGSize) {
super.init(frame: frame)
...
let gestureRecognizer = UITapGestureRecognizer(target: delegate!,
action: #selector(delegate!.handleTapFromView(_:, textField:
self)))
}
}
However, this is not the right syntax, as handleTapFromView(_:, textField: self) is invalid. This raises the following questions to which I haven't found a solution yet:
What exactly means this syntax? (_:). I assume it's passing itself, but the UITapGestureRecognizer is not created yet?
How do I successfully pass the TextField instance to the delegate alongside the sender?
I would suggest keeping things as simple as this,
protocol SomeDelegateProtocol: class {
func handletapFromView(_ sender: UITapGestureRecognizer, textField: UITextField)
}
class TextField: UITextField {
weak var someDelegate: SomeDelegateProtocol?
override init(frame: CGRect) {
super.init(frame: frame)
let tap = UITapGestureRecognizer.init(target: self, action: #selector(tap(_:)))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
#objc private func tap(_ sender: UITapGestureRecognizer) {
self.someDelegate?.handletapFromView(sender, textField: self)
}
}

Delegate methods not calling in UITextField custom subclass

I am creating a custom subclass from UITextField class. I want to apply something while textfield is focused. But in my custom class my delegate methods are not calling.
I have create a subclass that extends UITextField class and make some customisation.
In TGTextField class:
class TGTextField: UITextField, UITextFieldDelegate {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
delegate = self
createBorder()
}
required override init(frame: CGRect) {
super.init(frame: frame)
delegate = self
createBorder()
}
func createBorder(){
self.layer.borderColor = AppColor.TextFieldColors.BorderNormalColor.cgColor
self.layer.borderWidth = 1.0;
self.layer.cornerRadius = 8
}
func textFieldDidBeginEditing(textField: UITextField) {
print("focused")
self.activeTextFieldColor()
}
func textFieldDidEndEditing(textField: UITextField) {
print("lost focus")
self.deactiveTextFieldColor()
}
func activeTextFieldColor(){
self.layer.borderColor = AppColor.TextFieldColors.BorderActiveColor.cgColor
}
func deactiveTextFieldColor(){
self.layer.borderColor = AppColor.TextFieldColors.BorderNormalColor.cgColor
}
}
Both these delegates methods are not called.
func textFieldDidBeginEditing(textField: UITextField) {
print("focused")
self.activeTextFieldColor()
}
func textFieldDidEndEditing(textField: UITextField) {
print("lost focus")
self.deactiveTextFieldColor()
}
Your code works for me. These delegate methods in the custom class won't be called if you set text field delegate to the corresponding view controller after you've initialized the text fields.
To avoid this add target in TGTextField instead of UITextFieldDelegate
class TGTextField: UITextField {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
//delegate = self
createBorder()
}
required override init(frame: CGRect) {
super.init(frame: frame)
//delegate = self
createBorder()
}
func createBorder(){
self.layer.borderColor = UIColor.red.cgColor
self.layer.borderWidth = 1.0;
self.layer.cornerRadius = 8
addTarget(self, action: #selector(activeTextFieldColor), for: .editingDidBegin)
addTarget(self, action: #selector(deactiveTextFieldColor), for: .editingDidEnd)
}
#objc func activeTextFieldColor(){
self.layer.borderColor = UIColor.green.cgColor
}
#objc func deactiveTextFieldColor(){
self.layer.borderColor = UIColor.red.cgColor
}
}
Looks like you're implementing the wrong method signature; you should put _ before textField, like this
func textFieldDidBeginEditing(_ textField: UITextField) {}
func textFieldDidEndEditing(_ textField: UITextField) {}
Xcode should help you highlighting with a warning
Instance method 'textFieldDidBeginEditing(textField:)' nearly matches optional requirement 'textFieldDidBeginEditing' of protocol 'UITextFieldDelegate'

Can I chain delegates together?

Swift 4.0 iOS 11.x
I have created a simple text field class, that uses the UITextFieldDelegate. I wanted to add to it an additional protocol that I could use to pass on the fact that the text entry to said field completed. A Delegate chain, since once I have picked up the fact that text entry has exited in the custom class I cannot pass it down to the VC in which the UITextField class is within it seems.
import UIKit
protocol ExitedFieldDelegate {
func exited(info: String)
}
class IDText: UITextField, UITextFieldDelegate {
internal var zeus: ExitedFieldDelegate? = nil
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
delegate = self
}
required override init(frame: CGRect) {
super.init(frame: frame)
delegate = self
}
func textFieldDidBeginEditing(_ textField: UITextField) {
self.textColor = UIColor.black
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
if (delegate != nil) {
let info = self.text
zeus?.exited(info: info!)
}
}
}
I added this code to the viewController I wanted to use my custom class within.
class ConfigViewController: UIViewController, ExitedFieldDelegate
And of course the method required by the protocol
func exited(info: String) {
print("The brain has left the room")
}
And I made it a delegate of said protocol so I got this in effect
var blah = IDText()
blah.delegate = self
But well it doesn't work. Am I attempting the impossible here, should I simply use default notifications instead? or indeed something else?
By setting:
blah.delegate = self
You are overwriting setting the delegate to self in the initializers.
What you want is to rewrite:
internal var zeus: ExitedFieldDelegate? = nil
to:
weak var zeus: ExitedFieldDelegate?
To be able to use weak (you want that to prevent retain cycle), update protocol definition to:
protocol ExitedFieldDelegate: class {
func exited(info: String)
}
And then change this:
var blah = IDText()
blah.delegate = self
to:
var blah = IDText()
// you want to set zeus instead of the delegate field
blah.zeus = self

touch up inside (#IBAction) does not work with UIButton subclass

I created a subclass of UIButton:
import UIKit
#IBDesignable
class CheckboxButton: UIButton {
#IBInspectable var checkboxBackgroundColor: UIColor = Project.Color.baseGray
#IBInspectable var textColor: UIColor = Project.Color.mainDarkText
#IBInspectable var checkboxHighlightedBackgroundColor: UIColor = Project.Color.main
#IBInspectable var highlightedTextColor: UIColor = Project.Color.mainBrightText
// MARK: - Properties
var isChecked: Bool = false {
didSet {
changeState()
}
}
// MARK: - Overrides
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
if isChecked {
isChecked = false
} else {
isChecked = true
}
return false
}
override func prepareForInterfaceBuilder() {
changeState()
}
// MARK: - #IBActions
// MARK: - Functions
private func setupView() {
isUserInteractionEnabled = true
changeState()
}
private func changeState() {
if isChecked {
backgroundColor = checkboxHighlightedBackgroundColor
self.setTitleColor(highlightedTextColor, for: .normal)
} else {
backgroundColor = checkboxBackgroundColor
self.setTitleColor(textColor, for: .normal)
}
}
}
Now I added a button inside the storyboard and gave it the class CheckboxButton. Everything works. Then I added an IBAction like this:
#IBAction func pointBtnTapped(_ sender: CheckboxButton) {
print("tapped")
selectButton(withNumber: sender.tag)
}
But this doesn't work (nothing prints out). It works with a normal button, but not if the button is the subclass CheckboxButton. Do you have any ideas?
Edit: screenshots
https://www.dropbox.com/s/ewicc349ag9l6y2/Screenshot%202016-10-06%2023.41.39.png?dl=0
https://www.dropbox.com/s/vxevzscueproivc/Screenshot%202016-10-06%2023.42.33.png?dl=0
(couldn't embed them here. Don't know why)
Thank you!
You broke UIButton by overriding beginTracking() and always returning false. This brainwashes the button into thinking it's never being clicked.
What was your intent there? In any case, return true there and your code will fire the #IBAction.
EDIT: You're overthinking the issue by using a low-level method meant for highly customized behavior such as non-rectangular buttons. You just need:
How to use UIButton as Toggle Button?

Try to get UITextField from subviews, but getting UITextfieldLabel

I have a view contain multiple UITextField.
So when keyboard pop up I loop through the view to find out which textfield is first responder.
I try to print out all the view class, it show UITextFieldLabel instead of UITextField, anyone know what is this? I want to find out which textfiled getting focus.
Here is the code I use.
extension UIView{
func firstResponder() -> UIView?{
if self.isFirstResponder()
{
return self
}
for view in self.subviews
{
if view.isFirstResponder()
{
return view
}
}
return nil
}
}
UITextField has a protocol to which your view can conform to. When a textfield is selected or edited, you will get that textfield in your delegate method.
class myView: UIView, UITextFieldDelegate {
var anExampleTextField: UITextField?
override init(frame: CGRect) {
super.init(frame: frame);
self.anExampleTextField.delegate = self
}
//if using interface builder
override func awakeFromNib() {
super.awakeFromNib()
self.anExampleTextField.delegate = self
}
func textFieldDidBeginEditing(textField: UITextField) {
//The selected textfield will be passed here.
}
}

Resources