Custom UITextField class only applied to first text field - ios

I have made my first custom class in Swift and I want to use it for the text fields in my app. The problem is that it only works for the first textfield in the view controller, the class is not applied to the second one (the second one has no rounded corners, default placeholder color etc.). I have double checked that the right "custom class" is set in the storyboard for both textfields. Why isn't the class applied to both fields? Seems like a thing with a simple solution but I haven't found any...
Here is the class:
import UIKit
class RoundedUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
self.setAttributes()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func setAttributes() {
self.layer.cornerRadius = 20.0
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: self.frame.height))
self.leftView = paddingView
self.leftViewMode = UITextFieldViewMode.always
self.textColor = UIColor.white
self.alpha = 0.7
let str = NSAttributedString(string: (self.placeholder)!, attributes: [NSForegroundColorAttributeName:UIColor.white])
self.attributedPlaceholder = str
}
}
Here is the view controller code:
class LogInViewController: UIViewController {
#IBOutlet weak var password: RoundedUITextField!
#IBOutlet weak var userName: RoundedUITextField!
override func viewDidLoad() {
super.viewDidLoad()
userName.setAttributes()
// Do any additional setup after loading the view.
}
I discovered now that the problem lies in the "setAttributes", I thought the attributes where set in the class but they're actually only set in viewDidLoad for one of them (I put it there in the beginning and forgot to remove it)... I want this to be done in the "init" of the class for all of the fields...

Put your self.setAttributes() in your awakeFromNib method and remove it from init(frame: CGRect)
override func awakeFromNib() {
super.awakeFromNib()
self.setAttributes()
}
your custom class code will be like this
import UIKit
class RoundedUITextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
self.setAttributes()
}
func setAttributes() {
self.layer.cornerRadius = 20.0
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 15, height: self.frame.height))
self.leftView = paddingView
self.leftViewMode = UITextFieldViewMode.always
self.textColor = UIColor.white
self.alpha = 0.7
let str = NSAttributedString(string: (self.placeholder)!, attributes: [NSForegroundColorAttributeName:UIColor.white])
self.attributedPlaceholder = str
}
}
Hope this helps

Related

UITextField Custom Clear Button

I'm trying to implement custom clear button in text field using the solution on Custom Clear Button
It doesn't work, it shows default clear button. Any idea why? Following is my code:
class CustomTextField: UITextField {
override init(frame: CGRect) {
super.init(frame: frame)
let clearButton = UIButton(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
clearButton.setImage(UIImage(named: "Glyph/16x16/Clear")!, for: [])
self.rightView = clearButton
clearButton.addTarget(self, action: #selector(clearClicked), for: .touchUpInside)
self.clearButtonMode = .never
self.rightViewMode = .whileEditing
}
#objc override func clearClicked(sender:UIButton)
{
self.text = ""
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
As mentioned already, in your code the clearClicked method should not override as UITextField doesn't have a clearClicked method to override.
Anyway, I updated the code to work when using it with storyboards. Added the awakeFromNib method which calls the initialisation code.
class CustomTextField: UITextField {
override open func awakeFromNib() {
super.awakeFromNib()
self.initialize()
}
override init(frame: CGRect) {
super.init(frame: frame)
self.initialize()
}
func initialize() {
let clearButton = UIButton(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
clearButton.setImage(UIImage(named: "Glyph/16x16/Clear")!, for: [])
self.rightView = clearButton
clearButton.addTarget(self, action: #selector(clearClicked), for: .touchUpInside)
self.clearButtonMode = .never
self.rightViewMode = .whileEditing
}
#objc func clearClicked(sender:UIButton)
{
self.text = ""
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}

Creating UIView subclass in Xcode Playgrounds Programmatically

UIViewController and UIView class in Xcode Playgrounds
I am trying to figure out how to create a UIViewController in Xcode Playgrounds and attaching a UIView subclass to it.
I am quite new to swift and coding so am having some trouble.
class myView : UIView {
var label : UIButton!
var topHeader : UIImageView!
var nameText : UITextField!
var password : UITextField!
override init(frame: CGRect) {
super.init(frame: CGRect(x: 10, y: 10, width: 350, height: 450))
self.backgroundColor = UIColor.white
self.layer.borderColor = UIColor.black.cgColor
self.layer.borderWidth = 0.5
//place matters what gets loaded in first.
header("")
loginButton()
nameyText()
nameyText2()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
convenience init() {
self.init(frame: CGRect.zero)
}
func header(_ imageInsert: String){
let topHeader = UIImageView()
topHeader.frame = CGRect(x: -1, y: -1, width: 400, height: 125)
topHeader.backgroundColor = UIColor.white
topHeader.layer.borderWidth = 0.5
topHeader.translatesAutoresizingMaskIntoConstraints = true
topHeader.image = UIImage(named: imageInsert)
self.addSubview(topHeader)
}
func loginButton (){
//create properties for button
let label = UIButton(type: UIButtonType.roundedRect)
label.backgroundColor = .white
label.frame = CGRect(x: 135, y: 315, width: 75, height: 30)
label.setTitle("Login", for: UIControlState.normal)
label.layer.borderWidth = 0.5
label.layer.borderColor = UIColor.blue.cgColor
label.layer.cornerRadius = 4
self.addSubview(label)
}
func nameyText () {
let nameText = UITextField()
nameText.frame = CGRect(x: 45, y: 200, width: 250, height: 30)
nameText.backgroundColor = .white
nameText.borderStyle = .roundedRect
nameText.layer.borderColor = UIColor.lightGray.cgColor
nameText.placeholder = "Username"
nameText.keyboardAppearance = .default
self.addSubview(nameText)
}
func nameyText2 () {
let password = UITextField()
password.frame = CGRect(x: 45, y: 255, width: 250, height: 30)
password.backgroundColor = .white
password.borderStyle = .roundedRect
password.layer.borderColor = UIColor.lightGray.cgColor
password.placeholder = "Password"
password.keyboardAppearance = .default
password.isSecureTextEntry = true
self.addSubview(password)
}
}
This is the UIView subclass i created which looks like this...
UIView
I then created my main UIViewController class to add it to...
import UIKit
import PlaygroundSupport
public class ViewController : UIViewController, UITextFieldDelegate {
public override func viewDidLoad() {
super.viewDidLoad()
}
override public func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public override func loadView() {
//trying to make myView the root view for This ViewController
self.view = myView()
}
}
PlaygroundPage.current.liveView = ViewController()
However, when i add my UIView subclass to the UIViewController it looks like this...UIViewController
It's a different size and changing my UIView frame size does nothing.
Would like some help understanding why it does this, thanks.
You need to set the .preferredContentSize of the view controller. You can do this either explicitly, or by overriding it:
public class ViewController : UIViewController, UITextFieldDelegate {
override public var preferredContentSize: CGSize {
get { return self.view.bounds.size }
set { super.preferredContentSize = newValue }
}
public override func viewDidLoad() {
super.viewDidLoad()
}
override public func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
public override func loadView() {
//trying to make myView the root view for This ViewController
self.view = myView()
}
}

Swift UILabel subclass automatically call enum switch function

I have been creating a UILabel class called RPLabel, which is supposed to shorten all of my long list of programmatically set labels. This is the class code:
class RPLabel: UILabel {
// moneyTitle.frame = CGRect(x: 50, y: -50, width:XX, height: 35) //
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.setup()
self.testForLabelType()
}
enum labelTypeEnumeration {
case title, subtitle
}
var labelType = labelTypeEnumeration.title
override init(frame: CGRect){
super.init(frame: frame)
self.setup()
}
override func awakeFromNib() {
super.awakeFromNib()
self.setup()
}
func setup(){
self.text = self.text
self.textColor = self.textColor
self.font = self.font
self.layer.display()
}
func testForLabelType() {
switch labelType {
case .title:
setupTitle()
print("setupTitle")
case .subtitle:
setupSubtitle()
print("setupSubtitle")
}
}
func setupTitle(){
self.font = UIFont.boldSystemFont(ofSize: 12)
self.textColor = UIColor.secondaryColor()
self.textAlignment = .left
}
func setupSubtitle(){
self.font = UIFont.boldSystemFont(ofSize: 18)
self.textColor = UIColor.rgb(red: 200, green: 200, blue: 200)
self.textAlignment = .left
}
}
To make a label, I use the following piece of code:
var moneyTitle = RPLabel()
moneyTitle.labelType = .title
moneyTitle.testForLabelType()
moneyTitle.text = "MONEY"
moneyTitle.frame = CGRect(x: 50, y: -50, width:XX, height: 35)
The issue that I have is that I would like to set the labelType to .title without having to write moneyTitle.testForLabelType(). In other words, I would like for that function to run automatically in the class. An alternative I would not like would be inserting the parameter in the init, so please avoid telling me to do so, thanks.
You can use didSet:
didSet is called immediately after the new value is stored.
var labelType = labelTypeEnumeration.title {
didSet {
testForLabelType()
}
}

What's the correct way to add a UIImageView or UITextView to a custom UIButton class?

I've built a custom UIButton class but I'm struggling to add objects without affecting the behaviour of the button. I've shown the class below. When I use the class in my main code and add a target, the button only works in areas not covered by the image or text. How can I add objects and have the entire button area behave in the same way?
class TestButton: UIButton {
var myText: UITextView!
var myImageView: UIImageView!
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.blue
let myImage = UIImage(named: "AnImage")
myImageView = UIImageView(image: myImage)
myImageView.frame = CGRect(x: 10, y: 10, width: (myImage?.size.width)!, height: (myImage?.size.height)!)
addSubview(myImageView)
myText = UITextView()
myText.font = UIFont(name: "Courier", size: 12)!
myText.isEditable = false
addSubview(myText)
}
}
A guess here, hope it works.
UIImageView and UITextView does not normally allow "user interaction", meaning that the user can not tap them and expect the app to react based on that. That is probably why, when you tap on the Image view, that event is not passed through to the UIButton below.
Fortunately the fix is easy. You can set the boolean property isUserInteractionEnabled to true and you should be in business again.
So in your case:
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.blue
let myImage = UIImage(named: "AnImage")
myImageView = UIImageView(image: myImage)
myImageView.frame = CGRect(x: 10, y: 10, width: (myImage?.size.width)!, height: (myImage?.size.height)!)
myImageView.isUserInteractionEnabled = true
addSubview(myImageView)
myText = UITextView()
myText.font = UIFont(name: "Courier", size: 12)!
myText.isEditable = false
myText.isUserInteractionEnabled = true
addSubview(myText)
}
Update (after your comment)
OK so I just tried to create a quick project with your button and...it seems to work, I can click on the imageView and I can click on the label and still get an answer from my function, so there must be some difference in how we've set this up.
Here is my MyButton button, awfully close to the one you've made, the only difference is that I've added a backgroundColor to myImageView, a frame on myText and isUserInteractionEnabled = false on myText
class MyButton: UIButton {
var myText: UITextView!
var myImageView: UIImageView!
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor.blue
let myImage = UIImage(named: "AnImage")
myImageView = UIImageView(image: myImage)
myImageView.frame = CGRect(x: 10, y: 10, width: (myImage?.size.width)!, height: (myImage?.size.height)!)
myImageView.backgroundColor = UIColor.red
addSubview(myImageView)
myText = UITextView()
myText.font = UIFont(name: "Courier", size: 12)!
myText.frame = CGRect(x: 10, y: 80, width: 100, height: 30)
myText.isEditable = false
myText.isUserInteractionEnabled = false
addSubview(myText)
}
}
And here is my ViewController where I use the button
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let button = MyButton(frame: CGRect(x: 10, y: 100, width: 200, height: 200))
button.myText.text = "Hello"
button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
view.addSubview(button)
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func didTapButton(_ sender: MyButton) {
print("It's alive!!")
}
}
Which gives me this pretty UI
And when I tap either the red image, the blue button itself or the "Hello" label I can see this in my console:
It's alive!!
It's alive!!
It's alive!!
So the good news is that it seems to work, now we just need to figure out what the difference between your setup and my setup is :)
Hope that works and helps.

Subclassing UINavigationBar in Swift

I'm trying to create a custom UINavigationBar class and then use the Storyboard to set it as the class of my UINavigationController's NavigationBar.
Here's the code of my UINavigationBar class:
class CustomNavBar: UINavigationBar {
override func drawRect(rect: CGRect) {
super.drawRect(rect)
// Drawing code
self.backgroundColor = UIColor.orangeColor()
let myLabel = UILabel(frame: CGRect(x: 0, y: 4, width: 600, height: 36))
myLabel.backgroundColor = UIColor.purpleColor()
myLabel.textColor = UIColor.yellowColor()
myLabel.text = "Custom NavBar!"
self.addSubview(myLabel)
}
}
Then, in Interface Builder, I use the Identity Inspector to set this as the class of the NavigationBar of my UINavigationController.
When I run the App - it freezes. It hangs up on the LaunchScreen.xib and doesn't do anything.
Why is doing that? What's the right way to go about doing this?
On Swift:
File-New-File- iOS Source - Cocoa Touch class- Select Subclass of : UINavigationBar and Name it - CustomNavigationBar.
class CustomNavigationBar: UINavigationBar {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = UIColor.redColor()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
}
override func drawRect(rect: CGRect) {
}
}

Resources