Add dynamic type to a UISearchBar - ios

My question is pretty much stated in the title. I'm trying to add dynamic type (as defined here) to a UISearchBar with no luck. I know this is possible as the system apps seem to be able to handle it just fine as shown here:
However, my app doesn't seem to be handling that so well as shown here:
Knowing that UITextField is contained within UISearchBar I naturally tried this solution without success:
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).adjustsFontForContentSizeCategory = true
I've also tried searching online/checking documentation but I can't seem to find a solution anywhere. Is there something I'm missing to get dynamic type working in a UISearchBar.
Update:
#matt suggested I do a manual check and update the font that way. However, that is yielding another issue as the search bar itself is too small to fit the text as shown here:
#matt suggested to update the height as well using the scaledValue(for:) method, however this doesn't seem to work. Here's the code I'm using:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).font = UIFont.preferredFont(forTextStyle: .body)
let textFieldFrame = UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).frame
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).frame = CGRect(x: textFieldFrame.minX, y: textFieldFrame.minY, width: textFieldFrame.width, height: UIFontMetrics.default.scaledValue(for: textFieldFrame.height))
}
The font seems to now be scaling with this updated code, yet the search bar's height isn't growing:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
searchBar.textField?.font = UIFont.preferredFont(forTextStyle: .body)
if let textFieldFrame = searchBar.textField?.frame {
searchBar.textField?.frame = CGRect(x: textFieldFrame.minX, y: textFieldFrame.minY, width: textFieldFrame.width, height: UIFontMetrics.default.scaledValue(for: textFieldFrame.height))
}
}
Also, here's how I found the textField (just in case other users who get stuck would like to know):
extension UISearchBar {
var textField: UITextField? {
var _textField: UITextField? = nil
subviews.forEach {
$0.subviews.forEach {
if let textField = $0 as? UITextField {
_textField = textField
}
}
}
return _textField
}
}

I have followed these milestones to reach your goal:
Automatically Adjusts Font with the Dynamic Type feature (STEP 1).
Adapt the searchbar constraints (STEP 2) AND its textfield constraints (STEP 3) when a new preferred content size category occurs.
class SearchBarDynamicTypeVC: UIViewController {
#IBOutlet weak var mySearchBar: UISearchBar!
let fontHead = UIFont(name: "Chalkduster", size: 20.0)
let fontHeadMetrics = UIFontMetrics(forTextStyle: .title1)
var initialFrameHeight: CGFloat = 0.0
override func viewDidLoad() {
super.viewDidLoad()
UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).font = fontHeadMetrics.scaledFont(for: fontHead!)
mySearchBar.textField?.adjustsFontForContentSizeCategory = true //STEP 1
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
initialFrameHeight = mySearchBar.intrinsicContentSize.height
if let textField = mySearchBar.textField {
adaptConstraints(textField) //Initialization according to the first preferred content size category
}
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if let textField = mySearchBar.textField,
let _ = previousTraitCollection {
adaptConstraints(textField) // STEP 2 & 3
}
}
private func adaptConstraints(_ textField: UITextField) {
// Adapt the SEARCHBAR constraints
mySearchBar.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.deactivate(mySearchBar.constraints)
let heightSB = mySearchBar.heightAnchor.constraint(equalToConstant: fontHeadMetrics.scaledValue(for: initialFrameHeight))
let widthSB = mySearchBar.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - 20)
let centerVSB = mySearchBar.centerYAnchor.constraint(equalTo: self.view.centerYAnchor)
let centerHSB = mySearchBar.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
NSLayoutConstraint.activate([centerVSB,
centerHSB,
widthSB,
heightSB])
// Adapt the SEARCHBAR TEXTFIELD constraints
textField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.deactivate(textField.constraints)
let centerXTF = textField.centerXAnchor.constraint(equalTo: textField.superview!.centerXAnchor)
let centerYTF = textField.centerYAnchor.constraint(equalTo: textField.superview!.centerYAnchor)
let widthTF = textField.widthAnchor.constraint(equalTo: textField.superview!.widthAnchor, constant: -20.0)
let heightTF = textField.heightAnchor.constraint(equalTo: textField.superview!.heightAnchor, constant: -20.0)
NSLayoutConstraint.activate([centerXTF,
centerYTF,
widthTF,
heightTF])
}
}
I used the code snippet provided in your post to get the searchbar textfield:
extension UISearchBar {
var textField: UITextField? {
var _textField: UITextField? = nil
subviews.forEach {
$0.subviews.forEach {
if let textField = $0 as? UITextField {
_textField = textField
}
}
}
return _textField
}
}
However, you can also get it using the key searchField as follows:
let textField = searchBar.value(forKey: "searchField") as? UITextField
The snapshots hereunder show the final result:
You can now add dynamic type to a UISearchBar by adapting the code snippet above and customizing the visual personal choices (text style, font, margins...).

Related

Blinking cursor as default in Swift

How can I make cursor blink when the view is opened without touching anywhere. I am currently using becomeFirstResponder() My text field becomes really first responder but when the view is opened, blink does not blink. Why?
My code is here.
import UIKit
class ViewController: UIViewController {
let resultTextField: UITextField = {
var myField = UITextField()
myField.textColor = .blue
myField.font = .systemFont(ofSize: 36)
myField.textAlignment = .right
myField.borderStyle = .roundedRect
return myField
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(resultTextField)
resultTextField.becomeFirstResponder()
resultTextField.inputView = UIView()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let myWidth = self.view.frame.width
let myHeight = self.view.frame.height
resultTextField.frame = CGRect(x: (myWidth - (myWidth / 1.15))/2,
y: myHeight / 7.5,
width: myWidth / 1.15,
height: myHeight / 15)
}
}
Thanks
I agree with #Luca, try calling becomeFirstResponder in viewDidAppear or in your layoutSubviews function. viewDidLoad()only means that your UIViewController has been loaded to memory but is not displayed yet. Easy way to verify this is implementing a subclass from UITextField and override the caretRect which returns the cursor's frame. Set a breakpoint and test the code ...
class CustomTextField: UITextField {
override func caretRect(for position: UITextPosition) -> CGRect {
/// set a breakpoint and you will notice that it's not called with the viewDidLoad() of your UIViewController
return super.caretRect(for: position)
}
}

Material Components - Text Field - IOS

I'm newbie to swift programming, i need to design the login page with floating placeholder input. I have installed the MDCTextInput using POD.
added import
import MaterialComponents.MaterialTextFields
and in viewDidLoad() below code added,
companyID.placeholder = "Company ID"
companyID.placeholderLabel.highlightedTextColor = UIColor.white
companyID.placeholderLabel.textColor = UIColor.white
companyID.underline?.color = UIColor.white
companyID.delegate = self
i have followed the steps given in Material components in IOS
I am not clear about this line,
To achieve the animations and presentations defined by the guidelines (floating placeholders, character counts), a controller that conforms to protocol MDCTextInputController must be initialized to manage the text field.
I am not getting floating placeholder animation, how to do this in swift4 ? please anybody provide me an idea .
The Material iOS Github Link is:
material-components-ios
Use SkyFloatingLabelTextField Cocoa Pod. It's much easier to implement, You don't even have to write a single line of code. You can configure it from the storyboard. You can get it from here: https://github.com/Skyscanner/SkyFloatingLabelTextField
UITextField with floating label:
When you click on the TextField Placeholder will animate to upside with a Floating Label.
Create a Empty Swift Class Name FloatingLabeledTextField and Paste all code in that class.
Usage:
Drag UITextField from Object library. Select TextField in Xcode go to Identity Inspector assign class to FloatingLabeledTextField. Thats it.
import UIKit
class FloatingLabeledTextField: UITextField {
var floatingLabel: UILabel!
var placeHolderText: String?
var floatingLabelColor: UIColor = UIColor.blue {
didSet {
self.floatingLabel.textColor = floatingLabelColor
}
var floatingLabelFont: UIFont = UIFont.systemFont(ofSize: 15) {
didSet {
self.floatingLabel.font = floatingLabelFont
}
}
var floatingLabelHeight: CGFloat = 30
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let flotingLabelFrame = CGRect(x: 0, y: 0, width: frame.width, height: 0)
floatingLabel = UILabel(frame: flotingLabelFrame)
floatingLabel.textColor = floatingLabelColor
floatingLabel.font = floatingLabelFont
floatingLabel.text = self.placeholder
self.addSubview(floatingLabel)
placeHolderText = placeholder
NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidBeginEditing), name: UITextField.textDidBeginEditingNotification, object: self)
NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidEndEditing), name: UITextField.textDidEndEditingNotification, object: self)
}
#objc func textFieldDidBeginEditing(_ textField: UITextField) {
if self.text == "" {
UIView.animate(withDuration: 0.3) {
self.floatingLabel.frame = CGRect(x: 0, y: -self.floatingLabelHeight, width: self.frame.width, height: self.floatingLabelHeight)
}
self.placeholder = ""
}
}
#objc func textFieldDidEndEditing(_ textField: UITextField) {
if self.text == "" {
UIView.animate(withDuration: 0.1) {
self.floatingLabel.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: 0)
}
self.placeholder = placeHolderText
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
Drag Textfield in ViewController's view and Assign class to FloatingLabeledTextField in Identity Inspector.
Result:
To get the animation, you can create a var of any subclass of MDCTextInputControllerBaseclass ( <- these class confirms to the MDCTextInputControllerFloatingPlaceholder protocol <- This protocol again confirms to the MDCTextInputControllerprotocol). Create a var inside UIViewController and then init with textInput passing you MDCTextField.
WHY?
But to achieve the animations and presentations defined by the guidelines (floating placeholders, character counts), a controller that conforms to protocol MDCTextInputController must be initialized to manage the text field.
This means you need to initialise a variable of any of the MDCTextInputControllerBase class / subclass which confirms to the MDCTextInputController protocol
Enough talk. See some code:
final class SomeVC: UIViewController {
/* This is a subclass of MDCTextInputControllerBase */
var textFieldControllerFloating = MDCTextInputControllerUnderline()
/* For multiple textField */
var arrayOftextFieldControllerFloating = [MDCTextInputControllerUnderline]()
override func viewDidLoad() {
let textFieldFloating = MDCTextField()
self.view.addSubview(textFieldFloating)
textFieldFloating.placeholder = "Full Name"
textFieldFloating.delegate = self
textFieldControllerFloating = MDCTextInputControllerUnderline(textInput: textFieldFloating) // This will animate the textfield's place holder
/* If you have multiple textField */
arrayOftextFieldControllerFloating.append(MDCTextInputControllerUnderline(textInput: textFieldFloating1))
arrayOftextFieldControllerFloating.append(MDCTextInputControllerUnderline(textInput: textFieldFloating2))
arrayOftextFieldControllerFloating.append(MDCTextInputControllerUnderline(textInput: textFieldFloating3))
// Must have a MDCTextField / MDCMultilineTextField as textInput
}
}
extension SomeVC: UITextFieldDelegate {}
Note: You need to create a new controller for every MDCTextField or MDCMultilineTextField

Change UITextField height in UISearchBar - Swift 3

is there a way to change the height of a UISearchBar's textField??
I can access the textField like this and although background color changes, nothing seems to change in terms of frame/size...
I was able to change the searchBar height in IB by setting the constraints.
But the textfield stayed the same (44)...
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.mySearchBar.layoutIfNeeded()
self.mySearchBar.layoutSubviews()
self.mySearchBar.backgroundColor = UIColor.blue
for subView in mySearchBar.subviews
{
for subsubView in subView.subviews
{
if let textField = subsubView as? UITextField
{
var currentTextFieldBounds = textField.bounds
textField.borderStyle = UITextBorderStyle.none
currentTextFieldBounds.size.height = self.mySearchBar.bounds.height-10
textField.bounds = currentTextFieldBounds
textField.backgroundColor = UIColor.red
}
}
}
The UITextField within the UISearchBar is not directly accessible. You could create your own UISearchBarsubclass to emulate a regular Search bar. You could completely customize the UI as you see fit with either Interface builder or programatically.
protocol SearchBarEventDelegate {
func searchButtonPressed(searchBar: CustomSearchBar)
func searchBarDidReceiveInput(searchText: String)
func searchBarDidBackspace(searchText: String)
}
class CustomSearchBar: UIView {
var searchTextField: UITextField?
var delegate : SearchBarEventDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(searchTextField())
}
func searchTextField() -> UITextField {
//Input custom frame and attributes here.
let textField = UITextField(frame: CGRectZero)
textField.delegate = self
return textField
}
}
extension CustomSearchBar : UITextFieldDelegate {
//Implement Textfield delegate methods here.
//Propagate events to CustomSearchBar delegate. Example Provided.
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let partialSearchString = textField.text!
let fullSearchString = (partialSearchString as NSString).stringByReplacingCharactersInRange(range, withString: string)
if(range.length == 1) {
delegate?.searchBarDidBackspace(fullSearchString)
} else {
delegate?.searchBarDidReceiveInput(fullSearchString)
}
return true
}
}

UITextfield showing and dismissing very quickly in UIPageViewController (Swift)

I have a UIPageViewController as walkthrough presentation for my app. The walkthrough has basically 5 pages in total. Page 4 has a UITextField programmatically set. Don't mind the other objects like labels or Images.
The problem I have is that when the user reaches page 4, The user is presented with a Textfield which i'd like the keyboard to show up automatically via a becomeFirstResponder.
When I load this 4th view with the textfield, It shows up very quickly on the simulator and on my device and then goes back down. It basically shows up via the becomeFirstResponder code but somehow then resigns within 1 second.
I have tried this programmatically and also via the storyboard UITextfield to see if that made a difference but both seem to not work.
The code that executes a label is where I also executed the UITextField programmatically but for this example, I removed it and used an IBOutlet instead as you can see.
Also, in this case 3 I would put the becomeFirstResponder to activate the keyboard but it still did not work as expected.
Right now I left it in the viewWillAppear method as you can see.
Here is my code for this specific scenario:
import UIKit
class WalkthroughViewController: UIViewController {
#IBOutlet var headingLabel:UILabel!
#IBOutlet var contentLabel:UILabel!
#IBOutlet var contentImageView:UIImageView!
#IBOutlet var pageControl:UIPageControl!
#IBOutlet var forwardButton:UIButton!
// This was added via storyboard via drag and drop
#IBOutlet var nameField: UITextField!
// This is a UITextfield programmatically
let textField = UITextField(frame: CGRectMake(20, 200.0, 330.0, 40.0)) // x=x-cord, y=y-cord, Width, Height
// May 2 Updates
func textFieldFunc() {
textField.textAlignment = NSTextAlignment.Center
textField.textColor = UIColor.wetAsphaltColor()
textField.backgroundColor = UIColor.whiteColor()
textField.font = UIFont(name: "avenir", size: 21)
textField.borderStyle = UITextBorderStyle.None
textField.autocapitalizationType = UITextAutocapitalizationType.Words // If you need any capitalization
textField.becomeFirstResponder()
self.view.addSubview(textField)
}
func nameLabel() {
let label = UILabel(frame: CGRectMake(15, 180, 265, 33))
label.center = CGPointMake(185, 160)
label.textColor = UIColor.cloudsColor()
label.font = UIFont(name: "avenir", size: 30)
label.textAlignment = NSTextAlignment.Center
label.text = "Whats your name?"
self.view.addSubview(label)
}
#IBAction func submit(sender: AnyObject) {
// Thisis going to handle the name later and it will then reguster the user for later use within the app
}
var index = 0
var heading = ""
var imageFile = ""
var content = ""
override func viewDidLoad() {
super.viewDidLoad()
headingLabel.text = heading
contentLabel.text = content
contentImageView.image = UIImage(named: imageFile)
pageControl.currentPage = index
// 0...2
switch index {
case 0...2: forwardButton.setTitle("NEXT", forState: UIControlState.Normal)
nameField.hidden = true
// 3
case 3:
nameLabel()
nameField.hidden = false
case 4:
forwardButton.setTitle("DONE", forState: UIControlState.Normal)
default: break
}
print("Index: \(index)")
}
#IBAction func nextButtonTapped(sender: UIButton) {
switch index {
case 0...3: // 2
let pageViewController = parentViewController as! WalkthroughPageViewController
pageViewController.forward(index)
case 4: // 3
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setBool(true, forKey: "finishedWalkedThrough")
dismissViewControllerAnimated(true, completion: nil)
default: break
}
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if nameField.hidden == false {
nameField.becomeFirstResponder()
}
}
}
My question is, how can I remedy this so that when the 4th page is presented in a slide through manner, the UITextfield can present the keyboard like a normal view?
As I saw in a very similar post, This actually worked. I managed to solve it by using this:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if index == 3 {
dispatch_async(dispatch_get_main_queue(), {() -> Void in
let strongSelf: WalkthroughViewController = self
strongSelf.textField.becomeFirstResponder()
})
}
}
Now when I scroll to the 4th page (3rd from 0), It loads the keyboard with the .becomeFirstResponder as a normal UITextField would.
dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^{
[self.yourTextField becomeFirstResponder];
});
For Swift 3:
DispatchQueue.main.async(execute: {() -> Void in
let strongSelf: WalkthroughViewController = self
strongSelf. textField.becomeFirstResponder()
})
I didn't have to specify the index position of the ViewController

PlaceHolder animates when start typing in TextField in iOS

How to set this type of animation in UITextField? Nowadays, Many apps are using this.
I've found the solution. You can manage this type of animation using multiple labels, and show-hide those labels into textFieldDidBeginEditing method.
If you want nice animation same as you describe into your question, then try once following third party repository for UITextField.
JVFloatLabeledTextField
UIFloatLabelTextField
FloatLabelFields
If you are looking for the UITextView equivalent of this animation, please visit UIFloatLabelTextView repository.
This problem can be solved logically with the use of multiple labels and text-fields and later we can add animation if needed. I will like to explain this problem using three images, namely Img1, Img2 and Img3.
Img1 points to storyboard, where we have designed our interface. Here we have used three Labels each followed by TextField and UIView(line below Textfield).
Img2: It points to the initial screen when the app launches or when we press the "Sign up" Button at the bottom, which resets the screen. In this Image, the labels are hidden as textfields are blank with and view color is gray.
Img3: This image reflects the editing of Textfield. As we start editing text field(here the first one, namely name), the label shows up, size of textfield decreases, placeholder changes and color of view changes to black.
We need to keep one more thing in mind, when we stop editing any textfield and if it is still blank then set it properties to original.
I am adding code for this Question which I was asked as assignment in an interview.
import UIKit
class FloatingLabelViewController: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate {
//UITextFieldDelegate - protocol defines methods that you use to manage the editing and validation of text in a UITextField object. All of the methods of this protocol are optional.
//UINavigationControllerDelegate - Use a navigation controller delegate (a custom object that implements this protocol) to modify behavior when a view controller is pushed or popped from the navigation stack of a UINavigationController object.
#IBOutlet weak var NameLbl: UILabel!
#IBOutlet weak var EmailLbl: UILabel!
#IBOutlet weak var PasswordLbl: UILabel!
#IBOutlet weak var NameTxf: UITextField!
#IBOutlet weak var EmailTxf: UITextField!
#IBOutlet weak var PasswordTxf: UITextField!
#IBOutlet weak var SignUpBtn: UIButton!
#IBOutlet weak var NameView: UIView!
#IBOutlet weak var EmailView: UIView!
#IBOutlet weak var PasswordView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
NameTxf.delegate = self
EmailTxf.delegate = self
PasswordTxf.delegate = self
self.property()
//black is varaiable here
//setTitleColor - Sets the color of the title to use for the specified state
//var layer - The view’s Core Animation layer used for rendering. this propert is never nil
//cg color - Quartz color refernce
SignUpBtn.backgroundColor = UIColor.black
SignUpBtn.setTitleColor(UIColor.white, for: .normal)
SignUpBtn.layer.borderWidth = 1
SignUpBtn.layer.borderColor = UIColor.black.cgColor
//Tap guesture recognizer to hide keyboard
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(FloatingLabelViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
// UITapGestureRecognizer - UITapGestureRecognizer is a concrete subclass of UIGestureRecognizer that looks for single or multiple taps. For the gesture to be recognized, the specified number of fingers must tap the view a specified number of times.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//textFieldShouldReturn - Asks the delegate if the text field should process the pressing of the return button. The text field calls this method whenever the user taps the return button. YES if the text field should implement its default behavior for the return button; otherwise, NO.
// endEditing - Causes the view (or one of its embedded text fields) to resign the first responder status.
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
func dismissKeyboard() {
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
//When user Starts Editing the textfield
// textFieldDidBeginEditing - Tells the delegate that editing began in the specified text field
func textFieldDidBeginEditing(_ textField: UITextField) {
if textField == self.NameTxf
{
self.NameTxf.font = UIFont.italicSystemFont(ofSize: 15)
self.NameLbl.isHidden = false
self.NameLbl.text = self.NameTxf.placeholder
self.NameTxf.placeholder = "First Last"
NameView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
}
else if textField == self.EmailTxf
{
self.EmailTxf.font = UIFont.italicSystemFont(ofSize: 15)
self.EmailLbl.isHidden = false
self.EmailLbl.text = self.EmailTxf.placeholder
self.EmailTxf.placeholder = "abc#gmail.com"
EmailView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
}
else if textField == self.PasswordTxf
{
self.PasswordTxf.font = UIFont.italicSystemFont(ofSize: 15)
self.PasswordLbl.isHidden = false
self.PasswordLbl.text = self.PasswordTxf.placeholder
self.PasswordTxf.placeholder = "........."
PasswordView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
}
}
//When User End editing the textfield.
// textFieldDidEndEditing - Tells the delegate that editing stopped for the specified text field.
func textFieldDidEndEditing(_ textField: UITextField) {
//Checkes if textfield is empty or not after after user ends editing.
if textField == self.NameTxf
{
if self.NameTxf.text == ""
{
self.NameTxf.font = UIFont.italicSystemFont(ofSize: 25)
self.NameLbl.isHidden = true
self.NameTxf.placeholder = "Name"
NameView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
}
}
else if textField == self.EmailTxf
{
if self.EmailTxf.text == ""
{
self.EmailTxf.font = UIFont.italicSystemFont(ofSize: 25)
self.EmailLbl.isHidden = true
self.EmailTxf.placeholder = "Email"
EmailView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
}
}
else if textField == self.PasswordTxf
{
if self.PasswordTxf.text == ""
{
self.PasswordTxf.font = UIFont.italicSystemFont(ofSize: 25)
self.PasswordLbl.isHidden = true
self.PasswordTxf.placeholder = "Password"
PasswordView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
}
}
}
//Action on SingUp button Clicked.
#IBAction func signupClicked(_ sender: Any) {
self.property()
self.dismissKeyboard() //TO dismiss the Keyboard on the click of SIGNUP button.
}
//Function to set the property of Textfields, Views corresponding to TextFields and Labels.
func property(){
NameLbl.isHidden = true
EmailLbl.isHidden = true
PasswordLbl.isHidden = true
NameTxf.text = ""
EmailTxf.text = ""
PasswordTxf.text = ""
NameTxf.placeholder = "Name"
EmailTxf.placeholder = "Email"
PasswordTxf.placeholder = "Password"
self.NameTxf.font = UIFont.italicSystemFont(ofSize: 25)
self.EmailTxf.font = UIFont.italicSystemFont(ofSize: 25)
self.PasswordTxf.font = UIFont.italicSystemFont(ofSize: 25)
EmailTxf.keyboardType = UIKeyboardType.emailAddress
PasswordTxf.isSecureTextEntry = true
NameTxf.autocorrectionType = .no
EmailTxf.autocorrectionType = .no
NameView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
EmailView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
PasswordView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.5)
}
}
For Swift 4.0 and 4.2
Check this library for floating textField
https://github.com/hasnine/iOSUtilitiesSource
Code:
enum placeholderDirection: String {
case placeholderUp = "up"
case placeholderDown = "down"
}
public class IuFloatingTextFiledPlaceHolder: UITextField {
var enableMaterialPlaceHolder : Bool = true
var placeholderAttributes = NSDictionary()
var lblPlaceHolder = UILabel()
var defaultFont = UIFont()
var difference: CGFloat = 22.0
var directionMaterial = placeholderDirection.placeholderUp
var isUnderLineAvailabe : Bool = true
override init(frame: CGRect) {
super.init(frame: frame)
Initialize ()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
Initialize ()
}
func Initialize(){
self.clipsToBounds = false
self.addTarget(self, action: #selector(IuFloatingTextFiledPlaceHolder.textFieldDidChange), for: .editingChanged)
self.EnableMaterialPlaceHolder(enableMaterialPlaceHolder: true)
if isUnderLineAvailabe {
let underLine = UIImageView()
underLine.backgroundColor = UIColor.init(red: 197/255.0, green: 197/255.0, blue: 197/255.0, alpha: 0.8)
// underLine.frame = CGRectMake(0, self.frame.size.height-1, self.frame.size.width, 1)
underLine.frame = CGRect(x: 0, y: self.frame.size.height-1, width : self.frame.size.width, height : 1)
underLine.clipsToBounds = true
self.addSubview(underLine)
}
defaultFont = self.font!
}
#IBInspectable var placeHolderColor: UIColor? = UIColor.lightGray {
didSet {
self.attributedPlaceholder = NSAttributedString(string: self.placeholder! as String ,
attributes:[NSAttributedString.Key.foregroundColor: placeHolderColor!])
}
}
override public var placeholder:String? {
didSet {
// NSLog("placeholder = \(placeholder)")
}
willSet {
let atts = [NSAttributedString.Key.foregroundColor.rawValue: UIColor.lightGray, NSAttributedString.Key.font: UIFont.labelFontSize] as! [NSAttributedString.Key : Any]
self.attributedPlaceholder = NSAttributedString(string: newValue!, attributes:atts)
self.EnableMaterialPlaceHolder(enableMaterialPlaceHolder: self.enableMaterialPlaceHolder)
}
}
override public var attributedText:NSAttributedString? {
didSet {
// NSLog("text = \(text)")
}
willSet {
if (self.placeholder != nil) && (self.text != "")
{
let string = NSString(string : self.placeholder!)
self.placeholderText(string)
}
}
}
#objc func textFieldDidChange(){
if self.enableMaterialPlaceHolder {
if (self.text == nil) || (self.text?.count)! > 0 {
self.lblPlaceHolder.alpha = 1
self.attributedPlaceholder = nil
self.lblPlaceHolder.textColor = self.placeHolderColor
self.lblPlaceHolder.frame.origin.x = 0 ////\\
let fontSize = self.font!.pointSize;
self.lblPlaceHolder.font = UIFont.init(name: (self.font?.fontName)!, size: fontSize-3)
}
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 1, options: .curveEaseInOut, animations: {() -> Void in
if (self.text == nil) || (self.text?.count)! <= 0 {
self.lblPlaceHolder.font = self.defaultFont
self.lblPlaceHolder.frame = CGRect(x: self.lblPlaceHolder.frame.origin.x+10, y : 0, width :self.frame.size.width, height : self.frame.size.height)
}
else {
if self.directionMaterial == placeholderDirection.placeholderUp {
self.lblPlaceHolder.frame = CGRect(x : self.lblPlaceHolder.frame.origin.x, y : -self.difference, width : self.frame.size.width, height : self.frame.size.height)
}else{
self.lblPlaceHolder.frame = CGRect(x : self.lblPlaceHolder.frame.origin.x, y : self.difference, width : self.frame.size.width, height : self.frame.size.height)
}
}
}, completion: {(finished: Bool) -> Void in
})
}
}
func EnableMaterialPlaceHolder(enableMaterialPlaceHolder: Bool){
self.enableMaterialPlaceHolder = enableMaterialPlaceHolder
self.lblPlaceHolder = UILabel()
self.lblPlaceHolder.frame = CGRect(x: 0, y : 0, width : 0, height :self.frame.size.height)
self.lblPlaceHolder.font = UIFont.systemFont(ofSize: 10)
self.lblPlaceHolder.alpha = 0
self.lblPlaceHolder.clipsToBounds = true
self.addSubview(self.lblPlaceHolder)
self.lblPlaceHolder.attributedText = self.attributedPlaceholder
//self.lblPlaceHolder.sizeToFit()
}
func placeholderText(_ placeholder: NSString){
let atts = [NSAttributedString.Key.foregroundColor: UIColor.lightGray, NSAttributedString.Key.font: UIFont.labelFontSize] as [NSAttributedString.Key : Any]
self.attributedPlaceholder = NSAttributedString(string: placeholder as String , attributes:atts)
self.EnableMaterialPlaceHolder(enableMaterialPlaceHolder: self.enableMaterialPlaceHolder)
}
override public func becomeFirstResponder()->(Bool){
let returnValue = super.becomeFirstResponder()
return returnValue
}
override public func resignFirstResponder()->(Bool){
let returnValue = super.resignFirstResponder()
return returnValue
}
override public func layoutSubviews() {
super.layoutSubviews()
}
}
You can try using JSInputField which supports data validations as well.
JSInputField *inputField = [[JSInputField alloc] initWithFrame:CGRectMake(10, 100, 300, 50)];
[self.view addSubview:inputField];
[inputField setPlaceholder:#"Enter Text"];
[inputField setRoundedCorners:UIRectCornerAllCorners];
[inputField addValidationRule:JSCreateRuleNotNullValue]; //This will validate field for null value. It will show error if field is empty.
[inputField addValidationRule:JSCreateRuleNumeric(2)]; //This will validate field for numeric values and restrict to enter value upto 2 decimal places.
You can use SkyFloatingLabelTextField. It is SkyScanner's library for this kind of label or textField animations.
https://github.com/Skyscanner/SkyFloatingLabelTextField
I hope this answer will works for you.
Enjoy.
use this code
[your_textfieldname setShowsTouchWhenHighlighted:YES];

Resources