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'
Related
How can I set a default border color for UITextFields which are not in focus when the view appears? Tried this with no success:
class UITextFieldCustom : UITextField, UITextFieldDelegate {
init(frame: CGRect, size: CGFloat) {
super.init(frame: frame)
self.layer.borderColor = UIColor.gray.cgColor
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
If you can't see new border, try to increase its width:
layer.borderWidth = 2.0
The problem you are facing is that self.layer.borderColor = UIColor.gray.cgColor is not called, because the function init(frame: CGRect, size: CGFloat) is not called. The reason why it is not called is because your textfield is not initilized in your code, for example:
func createTextField() -> UITextfield {
return UITextfield(frame: .zero, size: 100.0)
}
Your textfield is initilized from the storyboard. That is why the other init function required init?(coder aDecoder: NSCoder) exists. The sotryboard calls this function to initalize the textfield.
To solve the problem you just need to add your border modification line into the other init function, like this:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.borderColor = UIColor.gray.cgColor
}
Although one other clean approach I prefere more, is to add all setup code into the viewDidLoad method, for a clean overview, like this:
class ViewController: UIViewController {
// MARK: - Properties
#IBOutlet weak var textfield: UITextfield!
// MARK: - View's Lifecycle
override func viewDidLoad {
super.viewDidLoad()
setupTextfield()
}
// MARK: - Setup
private func setupTextfield() {
textfield.layer.borderColor = UIColor.gray.cgColor
}
}
just place your code here as well, you probably don't call this from storyboard or nib.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.layer.borderColor = UIColor.gray.cgColor
}
use #IBDesignable class to create the border color and set the width, like this example.
import UIKit
#IBDesignable
class BorderTextField: UITextField {
#IBInspectable var borderColor: UIColor = UIColor.white{
didSet{
layer.borderColor = borderColor.cgColor
}
}
#IBInspectable var borderWidth: CGFloat = 0 {
didSet{
layer.borderWidth = borderWidth
}
}
}
the you can set the value in storyboard as needed.
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!)
I have added a custom class to UILabel.
Custom Class is:
#IBDesignable class CustomLabel: UILabel {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
private func setup() {
self.textColor = UIColor.blue
}
}
But I cant see the changes in storyboard. How can it is able to see the changes in the interface builder??
You have to add IBInspectable properties to see changes in storyboard
here is example
#IBDesignable class RoundedTextField: UITextField {
#IBInspectable var cornerRadius:CGFloat = 0 // You will see this in storyboard
#IBInspectable var borderColor:UIColor = .green // You will see this in storyboard
override func awakeFromNib() {
super.awakeFromNib()
self.borderStyle = .none
self.layer.cornerRadius = cornerRadius
self.layer.borderColor = borderColor.cgColor
self.layer.borderWidth = 2.0
self.backgroundColor = UIColor.white
self.layer.masksToBounds = true
}
}
Don't forgot to set class
Here how you can see in stoyrboard
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?
I'm new to swift and I'm just trying to create a subclass of uibutton. Except that I have this weird blue rounded rect appearing when the button is selected as shown below. When all I want is a nice white border.
The code of my class :
import UIKit
import QuartzCore
#IBDesignable
class ColorButton: UIButton {
//MARK: PROPERTIES
#IBInspectable var stickerColor: UIColor = UIColor.whiteColor() {
didSet {
configure()
}
}
override var selected: Bool {
willSet(newValue) {
super.selected = newValue;
if selected {
layer.borderWidth = 1.0
} else {
layer.borderWidth = 0.0
}
}
}
//MARK: Initializers
override init(frame : CGRect) {
super.init(frame : frame)
setup()
configure()
}
convenience init() {
self.init(frame:CGRectZero)
setup()
configure()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
configure()
}
override func awakeFromNib() {
super.awakeFromNib()
setup()
configure()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
configure()
}
func setup() {
//Border color
layer.borderColor = UIColor.whiteColor().CGColor
//Corner Radius
setUpCornerRadius()
}
func configure() {
backgroundColor = stickerColor
}
override func layoutSubviews() {
super.layoutSubviews()
setUpCornerRadius()
}
func setUpCornerRadius() {
layer.cornerRadius = CGRectGetWidth(bounds) * 0.205
}
}
I have checked your code. and I got same issue.
but If you set button type as Custom then this problem will not occur
Output :
Found something for buttonType :
You may find the discussion at CocoaBuilder's thread How to subclass UIButton? helpful, particularly Jack Nutting's suggestion to ignore the buttonType:
Note that this way the buttonType isn't explicitly set to anything,
which probably means that it's UIButtonTypeCustom. The Docs don't
seem to actually specify that, but since that's the 0 value in the
enum, that's likely what happens (and that seems to be the observable
behavior as well)
Source : https://stackoverflow.com/a/10278515/3202193