0

I am trying to add an image into my textinput in swiftui without the use of a zstack because this cause the whole view to bug, this is the expected result , is there a way to add them without the use of a stack? or should i adapt the whole code based on it ?

                                HStack {
                                    ZStack {
                                        CustomTextField(placeholder: "Email", text: $email, textColor: .black, isValid: emailValid)
                                            .focused($isEmailFocused)
                                        
                                        if let isValid = emailValid {
                                            Image(isValid ? "check_solid" : "cancel_solid")
                                                .resizable()
                                                .frame(width: 25, height: 25)
                                                .foregroundColor(isValid ? Color("greenstrokes") : Color("redstrokes"))
                                                .position(x: UIScreen.main.bounds.width - 100, y: 75)
                                        }
                                    }
                                }
3
  • Have you tried removing the ZStack and adding a Spacer() after the CustomTextField? Commented Oct 7, 2024 at 8:48
  • 1
    How about showing the image as an overlay over the CustomTextField, using alignment: .trailing? Commented Oct 7, 2024 at 8:49
  • Is this helpful: stackoverflow.com/questions/59058490 ? Commented Oct 7, 2024 at 9:05

2 Answers 2

0

While the overlay is the way to go for placing and aligning the image over the textfield, you should consider creating a view modifier for validation, so you can apply it to any textfield.

Otherwise, you will have repeated code and overlays everywhere, if you have multiple fields.

Here's a rough example that uses a view extension and a view modifier:

import SwiftUI

struct ValidateTextFieldView: View {
    
    @State private var inputText: String = ""
    @State private var inputNumber: Int?
    
    var body: some View {
        VStack(spacing: 10) {
            TextField("Type yes to confirm", text: $inputText)
                .padding()
                .background(.white)
                .clipShape(RoundedRectangle(cornerRadius: 8))
                .validateTextField($inputText)
                .textInputAutocapitalization(.never)
            
            Text("Press Enter to validate field")
                .font(.caption)
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundStyle(.secondary)
                .padding(.leading)
        }
        .padding()
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        .background(.background.secondary)
    }
}

extension View {
    
    func validateTextField(_ text: Binding<String>) -> some View {
        self
            .modifier(ValidateTextFieldModifier(text: text))
    }
}

struct ValidateTextFieldModifier: ViewModifier {
    
    //Parameters
    @Binding var text: String
    
    //State values
    @State private var isValid: Bool = false
    @State private var showValidation: Bool = false
    @State private var validationColor: Color = .clear
    
    //Body
    func body(content: Content) -> some View {
        content
            .onChange(of: text) {
                validationColor = .yellow
            }
            .onSubmit {
                if text == "yes" { //add your own validation logic
                    validationColor = .green
                }
                else { //if not valid
                    validationColor = .red
                }
            }
            .overlay(
                RoundedRectangle(cornerRadius: 8) // Rounded rectangle with a border
                    .stroke(validationColor, lineWidth: 2)
            )
            .overlay(alignment: . trailing) {
                Image(systemName: validationColor == .green ? "checkmark.circle.fill" : validationColor == .red ? "xmark.circle.fill" :  "")
                        .foregroundStyle(validationColor)
                        .padding(.trailing)
            }
    }
}

#Preview {
    ValidateTextFieldView()
}

I used a state to set the color depending on the validation result, but normally, you'd have a more refined method, like maybe using an enum for validation state, additional validation functions, maybe more parameters, etc.

Sign up to request clarification or add additional context in comments.

Comments

0

i think the best way is to use an overlay like this :

VStack(alignment: .leading, spacing: 3) {
                                HStack {
                                    CustomTextField(placeholder: "Email", text: $email, textColor: .black, isValid: emailValid)
                                        .focused($isEmailFocused)
                                        .overlay(
                                            Group {
                                                if let isValid = emailValid {
                                                    Image(isValid ? "check_solid" : "cancel_solid")
                                                        .resizable()
                                                        .frame(width: 25, height: 25)
                                                        .foregroundColor(isValid ? Color("greenstrokes") : Color("redstrokes"))
                                                        .padding(.trailing, 8)
                                                }
                                            },
                                            alignment: .trailing
                                        )
                                }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.