Floating text field in SwiftUI
SwiftUI has brought about a paradigm shift in UI development, allowing developers to create declarative and user-friendly interfaces effortlessly. When it comes to crafting forms or login screens, a floating text field can significantly improve the user experience by offering a clear and interactive input method. In this article, we will delve into a Swift implementation of a floating text field using SwiftUI.
Understanding the Code
Let's dissect the essential components of the provided Swift code.
enum TextFieldType {
case secureField
case textField
}
This enum defines two cases, secureField and textField, representing the types of text fields that can be created using this implementation.
struct SkyFloatingTextField: View {
// Properties
var placeholder: String
@Binding var text: String
var textFieldType: TextFieldType
@State private var isEditing = false
@State var isSecured: Bool = true
@FocusState var isSecureFieldFocused: Bool
@FocusState var isTextFieldFocused: Bool
@Environment(\.sizeCategory) var sizeCategory
// Computed Property
var shouldPlaceHolderMove: Bool {
isEditing || (text.count != 0)
}
// Body
var body: some View {
// Main VStack
VStack {
// Inner VStack for text field
VStack(alignment: .leading, spacing: 4) {
// HStack for text field and toggle button
HStack(spacing: 15) {
// Depending on the field type, render either SecureField or TextField
Group {
if isSecured {
// SecureField
SecureField("", text: $text, onCommit: {
withAnimation(.easeIn) {
isEditing = false
}
})
.focused($isSecureFieldFocused)
// Additional styling for SecureField
} else {
// TextField
TextField("", text: $text, onEditingChanged: { isEdit in
withAnimation(.easeIn) {
isEditing = isEdit
}
})
.accentColor(AppColors.textColor)
.font(.poppinsRegular(size: 16, category: sizeCategory))
.focused($isTextFieldFocused)
// Additional styling for TextField
}
}
.padding(.top, 12)
// Toggle button for secure field visibility
.overlay(alignment: .trailing) {
if textFieldType == .secureField {
Button {
isSecured.toggle()
} label: {
Image(systemName: isSecured ? "eye.slash" : "eye")
.foregroundColor(AppColors.textColor)
.frame(width: 15, height: 15)
.padding(13)
}
}
}
}
// Placeholder text animation
.background(
Text(placeholder)
.offset(y: shouldPlaceHolderMove ? -12 : 0)
.foregroundStyle(AppColors.textColor)
.font(.poppinsRegular(size: shouldPlaceHolderMove ? 11 : 15, category: sizeCategory))
, alignment: .leading
)
}
// Styling for the text field container
.frame(height: 50)
.padding(.horizontal, 8)
.background(
RoundedRectangle(cornerRadius: 8)
.stroke(AppColors.textColor, style: StrokeStyle(lineWidth: 0.5))
)
// Tap gesture to toggle focus on appearance
.onTapGesture {
withAnimation(.linear(duration: 8.0)) {
isSecureFieldFocused.toggle()
isTextFieldFocused.toggle()
}
}
// Set initial state for SecureField
.onAppear(perform: {
isSecured = textFieldType == .secureField
})
}
}
}

Join the conversation! Your thoughts help the community grow.