How to send multiple paramters in perform selector in swift3? - ios

I have to implement perform selector with multiple parameters (two strings parameters). I have created a function.
How to implement this function with perform selector after delay method.
func addBorderLayer(textField: UITextField , placeHolder: String) {
textField.layer.borderColor = UIColor.init(colorLiteralRed: 254/255, green: 93/255, blue: 49/255, alpha: 1.0).cgColor
textField.layer.borderWidth = 1.0
textField.placeholder = placeHolder
}`
I have call this method like this
self.perform(#selector(SecurityQuestionViewController.clearBorderLayer(textField:placeHolder:)), with:(textField,"Test") , afterDelay: 0.5)
When I pass parameter like this show me segmentation error in xcode,but my problem is how to pass parameters in it.What is correct way to pass parameters?

Use (G)rand (C)entral (D)ispatch, it's block based and easier to use than performSelector, you don't need to call an extra method, change the text field properties directly for example:
func addBorderLayer(textField: UITextField , placeHolder: String) {
textField.layer.borderColor = UIColor.init(colorLiteralRed: 254/255, green: 93/255, blue: 49/255, alpha: 1.0).cgColor
textField.layer.borderWidth = 1.0
textField.placeholder = placeHolder
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
textField.placeholder = "Test"
}
}

Related

Validate UITextField text letter by letter as it is entered

So I have a validation for my textfield, if the validation is true my button will be enabled and if the validation is false my button will be disable. The problem is the validation only runs after I click the done button in the keyboard.
I want the validation check letter by letter.
Here is my code:
func textFieldDidEndEditing(_ textField: UITextField) {
if (nomorTextField.text!.count >= 10) {
nextButton.isEnabled = true
nextButton.backgroundColor = #colorLiteral(red: 1, green: 0.4431372549, blue: 0.003921568627, alpha: 1)
if(nomorTextField.text!.count > 13) {
nextButton.isEnabled = false
nextButton.backgroundColor = #colorLiteral(red: 0.662745098, green: 0.662745098, blue: 0.662745098, alpha: 1)
}
else if emailTextFeild.text == "" {
nextButton.isEnabled = true
nextButton.backgroundColor = #colorLiteral(red: 1, green: 0.4431372549, blue: 0.003921568627, alpha: 1)
}
else if emailTextFeild.text?.isEmail == false {
nextButton.isEnabled = false
nextButton.backgroundColor = #colorLiteral(red: 0.662745098, green: 0.662745098, blue: 0.662745098, alpha: 1)
}
}
else {
nextButton.isEnabled = false
nextButton.backgroundColor = #colorLiteral(red: 0.662745098, green: 0.662745098, blue: 0.662745098, alpha: 1)
}
}
You can also connect it as an IBAction from storyboard (if you're using storyboards)
P.S. don't forget to change type to UITextField, and event to ValueChanged.
You should use a different delegate method -
textField(_:shouldChangeCharactersIn:replacementString:)
This method is called right before the characters are changed in the text field. You should always return true because in your case you are not looking to prevent text edits. However you do need to update the edited text field text with the new characters to make sure the count is correct.
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Casting String as NSString to be able to replace characters using NSRange easily.
guard let text = textField.text as NSString? else { return true }
// Get the length of the final text
let finalTextCount = text.replacingCharacters(in: range, with: string).count
// Setup the text count for the field depending on which one was edited
let nomorTextFieldCount = textField == nomorTextField ? finalTextCount :
nomorTextField.text!.count
if nomorTextFieldCount >= 10 {
nextButton.isEnabled = true
nextButton.backgroundColor = #colorLiteral(red: 1, green: 0.4431372549, blue: 0.003921568627, alpha: 1)
if nomorTextFieldCount > 13 {
nextButton.isEnabled = false
nextButton.backgroundColor = #colorLiteral(red: 0.662745098, green: 0.662745098, blue: 0.662745098, alpha: 1)
}else if emailTextFeild.text == "" {
nextButton.isEnabled = true
nextButton.backgroundColor = #colorLiteral(red: 1, green: 0.4431372549, blue: 0.003921568627, alpha: 1)
}else if emailTextFeild.text?.isEmail == false{
nextButton.isEnabled = false
nextButton.backgroundColor = #colorLiteral(red: 0.662745098, green: 0.662745098, blue: 0.662745098, alpha: 1)
}
}else{
nextButton.isEnabled = false
nextButton.backgroundColor = #colorLiteral(red: 0.662745098, green: 0.662745098, blue: 0.662745098, alpha: 1)
}
return true
}

How to grab color for UISearchBar?

As we know we change text color of SearchBar by this line of code and it works good:
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).defaultTextAttributes = [NSAttributedStringKey.foregroundColor.rawValue: UIColor.blue]
And the placeholder for color is UIColor.blue.
The questions is:
How to grab specific color?
I have tried to change UIColor.blue to UIColor.init(red: 200, green: 200, blue: 200, alpha: 1)
However no matter what number of red/green/blue/alpha i provide to init() i cannot grab a color.
Is there an Enum limitation like .blue/.red/.yellow?
What i am doing wrong?
public extension UISearchBar
{
public func SetSearchbarcolor(srchcolor: UIColor)
{
let Search = subviews.flatMap { $0.subviews }
guard let Searchfilter = (Search.filter { $0 is UITextField }).first as? UITextField else { return }
Searchfilter.textColor = srchcolor
}
}
Output : Searchbar_name.SetSearchbarcolor(srchcolor: UIColor.colorname)
Instead of UIColor.init, try
UIColor(red: 100/255, green: 100/255, blue: 100/255, alpha: 1)

Function to style TextField borders in swift not working

so I am new to Swift and mobile development, I want to make function that Change TextField style so i don't have to write long code for each TextField i have.
This is what I am trying to do :
func borderstyle(TextField : UITextField){
self.TextField.layer.borderColor = UIColor(red: 46/225, green: 204/225, blue: 113/225, alpha: 1).CGColor;
self.TextField.layer.borderWidth = CGFloat(Float(1.0));
self.TextField.layer.cornerRadius = CGFloat(Float(0.0));
}
I think you can get what i am trying to make form the code , the problem is that TextField in the func is read as #IBOutlet while its not.
I want to style any TextField I have with something like this :
borderstyle(UserNameTextField) // UserNameTextField is #IBOutlet
I know that I am doing some kind of mistake there but I want to know whats the best way to solve that.
Thanks.
Why you pass a textField to the function and then you use self.textField inside of it?
Use:
TextField.layer.borderColor = UIColor(red: 46/225, green: 204/225, blue: 113/225, alpha: 1).CGColor;
TextField.layer.borderWidth = CGFloat(Float(1.0));
TextField.layer.cornerRadius = CGFloat(Float(0.0));
Remove the self pointer from the code.
func borderstyle(textField : UITextField){
textField.layer.borderColor = UIColor(red: 46/225, green: 204/225, blue: 113/225, alpha: 1).CGColor;
textField.layer.borderWidth = CGFloat(Float(1.0));
textField.layer.cornerRadius = CGFloat(Float(0.0));
}
NB: As a good naming concept follow camelCase as shown

I'd like to create a CAGradientLayer Subclass/Utility class

I've been programming in one way or another for 30+ years, but I'm new to Swift and iOS programming and working on my first app. I've worked out how to create a CAGradientLayer to show a gradient on screen, but I'd like to create a utility class/extension/subclass with some predefined gradients in it.
I am assuming I can do this by creating subclasses of CAGradientLayer with the properties pre-set at initialisation time, but I'm not sure of the correct syntax to do this. I guess I am missing some basic Swift requirements?
I've tried the following:
let greenBlueGradient = GreenBlueGradient.greenBlueGradient()
class GreenBlueGradient: CAGradientLayer {
override init() {
super.init()
}
func greenBlueGradient() -> GreenBlueGradient {
self.colors = [ UIColor.init( red: 0.05, green: 0.75, blue: 0.91, alpha: 1.0 ).CGColor, UIColor.init( red: 0.56, green: 0.93, blue: 0.56, alpha: 1.0 ).CGColor ]
return self
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
But I'm getting the error "Missing argument for parameter #1 in call" on the let line. What am I missing? Surely there is a more efficient way of doing this? I sort of have in my head that I will be able to create some sort of utility class/extension that will return a CAGradientLayer with the colors already set ready for me to set the frame and insert it into my view hierarchy.
You shoud add an extension of CAGradientLayer in other file for exemple :
in file "UIExtensionsCAGradientLayer.swift"
extension CAGradientLayer {
func setupGreenBlurGradient(){
self.colors = [UIColor.init( red: 0.05,
green: 0.75,
blue: 0.91,
alpha: 1.0).CGColor,
UIColor.init( red: 0.56,
green: 0.93,
blue: 0.56,
alpha: 1.0 ).CGColor ]
}
}
Then in the file where you need the green blur gradient you do :
let greenGradientBlur = CAGradientLayer(layer : layer)
greenGradientBlur.setupGreenBlueGradient()
The error message here is a bit misleading. (File a bug about that. Or fix it yourself, if you're so inclined, now that Swift is open source.)
Your attempt to call GreenBlueGradient.greenBlueGradient() fails because you're calling an instance method as if it were a class method. That call would succeed if you'd declared greenBlueGradient() as a class func. However, that function's implementation relies on self.
What you probably want instead is to add your customization to init:
override init() {
super.init()
self.colors = [
UIColor(red: 0.05, green: 0.75, blue: 0.91, alpha: 1.0).CGColor,
UIColor(red: 0.56, green: 0.93, blue: 0.56, alpha: 1.0).CGColor,
]
}
That way, a client can get your custom gradient just by constructing an instance:
let greenBlueGradient = GreenBlueGradient()
Pretty colors, by the way.

How can I properly group and minimize style code for UITextfields?

I'm trying to implement a standard universal styling of my text fields based strictly on the login/sign up fields.
So, I designed them all to be identical, but I think that I'm reusing a lot of code that can be condensed and maybe used in a variable? I'm not sure how to do so.
The way it is works, but i'm sure it can be done better than this. I'm almost certain there's a way to minimize this code for better practice.
I'm still learning, so I really want to learn better practice in dev.
Here's an example of my sign up view & the styling of the fields:
class JoinVC: UIViewController, UITextFieldDelegate {`
#IBOutlet weak var enterEmailTextField: UITextField!
#IBOutlet weak var enterPasswordTextField: UITextField!
#IBOutlet weak var enterNameTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Field Border Corner + Width
self.enterEmailTextField.layer.cornerRadius = 24.0
self.enterEmailTextField.layer.borderWidth = 1.5
self.enterPasswordTextField.layer.cornerRadius = 24.0
self.enterPasswordTextField.layer.borderWidth = 1.5
self.enterNameTextField.layer.cornerRadius = 24.0
self.enterNameTextField.layer.borderWidth = 1.5
// ...
// Field Placeholder ColorEnter
var placeholderEnterEmail = NSAttributedString(string: "Enter Email", attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
var placeholderEnterPass = NSAttributedString(string: "Choose Password", attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
var placeholderEnterName = NSAttributedString(string: "Choose Username", attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
enterEmailTextField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
enterPasswordTextField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
enterNameTextField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
// ...
// Text Field Border color
var borderColor : UIColor = UIColor( red: 255, green: 255, blue:255, alpha: 0.8 )
self.enterPasswordTextField.layer.borderColor = borderColor.CGColor; enterEmailTextField.attributedPlaceholder = placeholderEnterEmail;
self.enterEmailTextField.layer.borderColor = borderColor.CGColor; enterPasswordTextField.attributedPlaceholder = placeholderEnterPass;
self.enterNameTextField.layer.borderColor = borderColor.CGColor; enterNameTextField.attributedPlaceholder = placeholderEnterName;
// ...
}
}
The way I have solved this before, especially if all text fields in the project are:
Always going to have identical attributes,
Always going to be created from the storyboard
is to subclass UITextField and apply the attributes in -awakeFromNib:
class KBTextField: UITextField {
let myAttributes = [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)]
let mySublayerTransform = CATransform3DMakeTranslation(20, 0, 0)
let myBorderColor = UIColor( red: 255, green: 255, blue:255, alpha: 0.8 )
override func awakeFromNib () {
self.layer.sublayerTransform = mySublayerTransform
self.layer.borderColor = myBorderColor.CGColor
self.layer.cornerRadius = 24.0
self.layer.borderWidth = 1.5
self.attributedPlaceholder = NSAttributedString(string: self.placeholder!, attributes: myAttributes)
}
}
Then you can just set the class right on the storyboard (to KBTextField, in this case) and it will take care of all your attributes automatically.
This way, you can ensure that all KBTextFields in your app look identical, as long as you create them through the storyboard.
easy solution for reusable code is a handler
func setupTextField(textField : UITextField, placeHolderString: String)
{
let borderColor = UIColor( red: 1.0, green: 1.0, blue:1.0, alpha: 0.8 )
textField.layer.cornerRadius = 24.0
textField.layer.borderWidth = 1.5
textField.layer.sublayerTransform = CATransform3DMakeTranslation(20, 0, 0);
textField.layer.borderColor = borderColor.CGColor;
textField.attributedPlaceholder = NSAttributedString(string: placeHolderString, attributes: [NSForegroundColorAttributeName : UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)])
}
override func viewDidLoad() {
super.viewDidLoad()
setupTextField(enterEmailTextField, placeHolderString: "Enter Email")
setupTextField(enterPasswordTextField, placeHolderString: "Choose Password")
setupTextField(enterNameTextField, placeHolderString: "Choose Username")
}
Note: UIColor values must be in the range of 0.0 to 1.0
You can use the Extension functionality.
Just create an Extension of UITextField an place your code into that Extension
(easy tutorial here)
Ex:
extension UITextField
{
func setPlaceholderColorAndString(pholder: String, color: UIColor)
{
self.attributedPlaceholder = NSAttributedString(string:pholder,
attributes:[NSForegroundColorAttributeName: color])
}
func setupField()
{
self.layer.cornerRadius = 24.0
self.layer.borderWidth = 1.5
}
}
Then in your code you can use it like:
self.enterEmailTextField.setPlaceholderColorAndString(pholder: "Enter Email", color: UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)
self.enterEmailTextField.setupField()
self.enterPasswordTextField.setPlaceholderColorAndString(pholder: "Enter Password", color: UIColor(red: 255/255, green: 255/255, blue:255/255, alpha: 0.6)
self.enterPasswordTextField.setupField()
And so on. Of course the above snippet it's only to give you an idea how using it, you can improve it a lot to fit your needs.

Resources