Creating a custom floating label style text field in swift

Boleigha Mark
Sprinthub Engineering
4 min readOct 9, 2019

So recently, I had to implement a Gmail style floating label text field in an app. The floating label input style has been around for quite a while since it was created by designer Matt D Smith. Let's take a look at the form below

Floating label input animation
The float label form interaction by Matt D Smith

The interaction is quite simple, float the label above the input field when the field is selected and remove the placeholder. When the field loses focus, bring back the placeholder and remove the label if the field is empty. Well, iOS has a default text field; UITextField which we can customise to achieve this effect. There are two ways to go about this, with storyboards and without. Let's get to work!!!

Step 1: Create a swift file to hold our customization code. For the sake of this tutorial, we’ll call it “FloatinLabelInput” (FloatingLabelInput.swift). This file will hold the code responsible for creating and animating the floating label. Create a class using the same name extending UITextField like in the code below:

FloatingLabelInput.swift

Next, we need to create our custom values and initializers to allow us to override the default UITextField implementation. We will be marking the values with the “@IBInspectable” keyword so we can set them in our interface builder; for those who love to use storyboards.

First, our values, copy and paste the code below into your FloatingLabelInput class

var floatingLabel: UILabel = UILabel(frame: CGRect.zero) // Label
var floatingLabelHeight: CGFloat = 14 // Default height
@IBInspectable
var
_placeholder: String? // we cannot override 'placeholder'
@IBInspectable
var
floatingLabelColor: UIColor = UIColor.black {
didSet {
self.floatingLabel.textColor = floatingLabelColor
self.setNeedsDisplay()
}
}
@IBInspectable
var
activeBorderColor: UIColor = UIColor.blue
@IBInspectable
var
floatingLabelFont: UIFont = UIFont.systemFont(ofSize: 14) {
didSet {
self.floatingLabel.font = self.floatingLabelFont
self.font = self.floatingLabelFont
self.setNeedsDisplay()
}
}

Second, Our initializer. copy and paste this just below the last variable

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self._placeholder = (self._placeholder != nil) ? self._placeholder : placeholder // Use our custom placeholder if none is set
placeholder = self._placeholder // make sure the placeholder is shown
self.floatingLabel = UILabel(frame: CGRect.zero) self.addTarget(self, action: #selector(self.addFloatingLabel), for: .editingDidBegin)
self.addTarget(self, action: #selector(self.removeFloatingLabel), for: .editingDidEnd)
}

As we can see from the code above, we attach a listener to our text field to fire when the user focuses on a text field and when the cursor is removed. now we just need the logic to add/remove our floating label. Please add the code below:

// Add a floating label to the view on becoming first responder@objc func addFloatingLabel() {
if self.text == "" {
self.floatingLabel.textColor = floatingLabelColor
self.floatingLabel.font = floatingLabelFont
self.floatingLabel.text = self._placeholder
self.floatingLabel.layer.backgroundColor = UIColor.white.cgColor
self.floatingLabel.translatesAutoresizingMaskIntoConstraints = false
self
.floatingLabel.clipsToBounds = true
self
.floatingLabel.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.floatingLabelHeight)
self.layer.borderColor = self.activeBorderColor.cgColor
self.addSubview(self.floatingLabel)

self.floatingLabel.bottomAnchor.constraint(equalTo:
self.topAnchor, constant: -10).isActive = true // Place our label 10pts above the text field
// Remove the placeholder
self.placeholder = ""
}
self.setNeedsDisplay()
}

What the code above does is quite simple, set a text for our label, add it as a subview to our input field and activate layout constraints to position it properly on the screen, then remove the placeholder. we used UIView.animate to achieve a simple slide up animation. Next, we need to be able to remove our label. add the code below

@objc func removeFloatingLabel() {
if self.text == "" {
UIView.animate(withDuration: 0.13) {
self.subviews.forEach{ $0.removeFromSuperview() }
self.setNeedsDisplay()
}
self.placeholder = self._placeholder
}
self.layer.borderColor = UIColor.black.cgColor
}

Step 2: We create our text field in our storyboard and assign it’s class to our custom `UITextField` class like below

Next, we connect it to an IBOutlet by dragging from our storyboard to our while holding our ViewController like below

We are done. now we have a custom floating label style input field. lets see a small demo of our code in action

The code is on Github. feel free to fork, modify and make it better.

--

--