Floating Text Field In SwiftUI
In this article, We will explore how to implement a Floating Text Field Using SwiftUI
Before proceeding, please consider subscribing to our YOUTUBE CHANNEL
It gives us a lot of motivation to produce high-quality content for you guys.
if you are interested in watching the video tutorial, Check out below.
Let's start by creating the script FloatingTextField
struct FloatingTextField: View {
var body: some View {
ZStack(alignment: .leading){
}
}
}
We need a few variables to start with which include placeholderText
and few others
struct FloatingTextField: View {
let placeholderText: String
@State private var text: String = ""
let animation: Animation = .spring(response: 0.1, dampingFraction: 0.6)
@State private var placeholderOffset: CGFloat
@State private var scaleEffectValue: CGFloat
private var onTextAction: ((_ oldValue: String, _ newValue: String) -> ())?
init(placeholderText: String, placeholderOffset: CGFloat = 0, scaleEffectValue: CGFloat = 1, onTextAction: ((_: String, _: String) -> Void)? = nil) {
self.placeholderText = placeholderText
self.placeholderOffset = placeholderOffset
self.scaleEffectValue = scaleEffectValue
self.onTextAction = onTextAction
}
var body: some View {
ZStack(alignment: .leading){
}
}
}
We’ll be using a Text
view and TextField
which is added to the ZStack
. Also under the overlay
a RoundedRectangle
is added.
struct FloatingTextField: View {
let placeholderText: String
@State private var text: String = ""
let animation: Animation = .spring(response: 0.1, dampingFraction: 0.6)
@State private var placeholderOffset: CGFloat
@State private var scaleEffectValue: CGFloat
private var onTextAction: ((_ oldValue: String, _ newValue: String) -> ())?
init(placeholderText: String, placeholderOffset: CGFloat = 0, scaleEffectValue: CGFloat = 1, onTextAction: ((_: String, _: String) -> Void)? = nil) {
self.placeholderText = placeholderText
self.placeholderOffset = placeholderOffset
self.scaleEffectValue = scaleEffectValue
self.onTextAction = onTextAction
}
var body: some View {
ZStack(alignment: .leading){
Text(placeholderText)
.foregroundStyle($text.wrappedValue.isEmpty ? Color.white : .gray)
.font($text.wrappedValue.isEmpty ? .headline : .caption)
.offset(y: placeholderOffset)
.scaleEffect(scaleEffectValue, anchor: .leading)
TextField("", text: $text)
.font(.headline)
.foregroundStyle(Color.yellow)
}
.padding()
.padding(.vertical, 5)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.gray, lineWidth: 2)
}
}
}
Let's use this FloatingTextField
inside our ContentView
struct ContentView: View {
var body: some View {
ZStack {
Color.black
.ignoresSafeArea()
ZStack {
FloatingTextField(placeholderText: "Name")
}
.padding()
}
}
}
As you can see, there is no way to tell if text is changed or not.
To fix this, we added a onTextChange
modifier.
extension FloatingTextField {
public func onTextChange(_ onTextAction: @escaping ((_ oldValue: String, _ newValue: String) -> ())) -> Self {
var view = self
view.onTextAction = onTextAction
return view
}
}
This modifier is called onChange
function.
struct FloatingTextField: View {
let placeholderText: String
@State private var text: String = ""
let animation: Animation = .spring(response: 0.1, dampingFraction: 0.6)
@State private var placeholderOffset: CGFloat
@State private var scaleEffectValue: CGFloat
private var onTextAction: ((_ oldValue: String, _ newValue: String) -> ())?
init(placeholderText: String, placeholderOffset: CGFloat = 0, scaleEffectValue: CGFloat = 1, onTextAction: ((_: String, _: String) -> Void)? = nil) {
self.placeholderText = placeholderText
self.placeholderOffset = placeholderOffset
self.scaleEffectValue = scaleEffectValue
self.onTextAction = onTextAction
}
var body: some View {
ZStack(alignment: .leading){
Text(placeholderText)
.foregroundStyle($text.wrappedValue.isEmpty ? Color.white : .gray)
.font($text.wrappedValue.isEmpty ? .headline : .caption)
.offset(y: placeholderOffset)
.scaleEffect(scaleEffectValue, anchor: .leading)
TextField("", text: $text)
.font(.headline)
.foregroundStyle(Color.yellow)
}
.padding()
.padding(.vertical, 5)
.overlay {
RoundedRectangle(cornerRadius: 10)
.stroke(.gray, lineWidth: 2)
}
.onChange(of: text) { oldValue, newValue in
withAnimation(animation) {
placeholderOffset = $text.wrappedValue.isEmpty ? 0 : -25
scaleEffectValue = $text.wrappedValue.isEmpty ? 1 : 0.75
}
onTextAction?(oldValue, newValue)
}
}
}
after adding this modifier, our code looks like below.
struct ContentView: View {
var body: some View {
ZStack {
Color.black
.ignoresSafeArea()
ZStack {
FloatingTextField(placeholderText: "Name")
.onTextChange { oldValue, newValue in
print(newValue)
}
}
.padding()
}
}
}
That’s it. Below is what we get.
Once again Thanks for stopping by.
Do check out our YOUTUBE CHANNEL
Social Handles
Instagram : https://www.instagram.com/mobileappsacademy/
Twitter : https://twitter.com/MobileAppsAcdmy
LinkedIn : https://www.linkedin.com/company/mobile-apps-academy/