2

I wanted to implement feature to show and hide the password in SecureField. below is code for SecureField I had added button which will get detected to show and hide the text in SecureField. But swiftUI does not have feature similar to isSecureTextEntry Is there any other way instead of toggle between Textfield and SecureField here

SecureField(placeholder, text: $textValue, onCommit: {
    onReturn?()
})
.onTapGesture {
    onBegin?()
}
.keyboardType(keyboardType)
.font(Font.label.bodyDefault)
.disableAutocorrection(true)
.frame(maxWidth: .infinity, maxHeight: 40)
.padding(.leading)
Andrew
  • 26,706
  • 9
  • 85
  • 101
sweta dodiya
  • 49
  • 1
  • 5
  • The linked option is the best option unless you want to get into `UIViewRepresentable` which is far more complex than this. – xTwisteDx Dec 27 '21 at 05:18

2 Answers2

5

This is not as straightforward as it should be. One of the answers there is pretty close, but it doesn't quite cover everything as it has a poor implementation of @FocusState. iOS 15 definitely made this field easier to construct, as there are two keys: 1. using .opacity() to show and hide the fields, 2. using @FocusState to make a seamless transition between the two fields. The only downside to this method is in order to make the transition seamless, you must restrict the keyboard to only ASCII-compatible characters, so some languages are left out, such as Russian.

struct CustomSecureField: View {
    
    @FocusState var focused: focusedField?
    @State var showPassword: Bool = false
    @Binding var password: String
    
    var body: some View {
        HStack {
            ZStack(alignment: .trailing) {
                TextField("Password", text: $password)
                    .focused($focused, equals: .unSecure)
                    .autocapitalization(.none)
                    .disableAutocorrection(true)
                // This is needed to remove suggestion bar, otherwise swapping between
                // fields will change keyboard height and be distracting to user.
                    .keyboardType(.alphabet)
                    .opacity(showPassword ? 1 : 0)
                SecureField("Password", text: $password)
                    .focused($focused, equals: .secure)
                    .autocapitalization(.none)
                    .disableAutocorrection(true)
                    .opacity(showPassword ? 0 : 1)
                Button(action: {
                    showPassword.toggle()
                    focused = focused == .secure ? .unSecure : .secure
                }, label: {
                    Image(systemName: self.showPassword ? "eye.slash.fill" : "eye.fill")
                        .padding()
                })
            }
        }
    }
    // Using the enum makes the code clear as to what field is focused.
    enum focusedField {
        case secure, unSecure
    }
}
Yrb
  • 8,103
  • 2
  • 14
  • 44
1

Accepted answer (Yrb answers) is not working properly, when switch the eye to visible pass and enter some password and again switch back to secure mode and enter some character, the field will be empty and all entered characters will be gone.

It's my solution that doesn't have any dependency on iOS 15 too:

struct CustomSecureField: View {

@State var isPasswordVisible: Bool = false
@Binding var password: String
var placeholder = ""

var body: some View {
    HStack(spacing: 12) {
        ZStack {
            if password.isEmpty {
                HStack {
                    Text(placeholder)
                    Spacer()
                }
            }
            
            ZStack {
                TextField("",
                          text: $password)
                .frame(maxHeight: .infinity)
                .opacity(isPasswordVisible ? 1 : 0)
                
                SecureField("",
                            text: $password)
                .frame(maxHeight: .infinity)
                .opacity(isPasswordVisible ? 0 : 1)
            }
        }
        .padding(.horizontal, 8)
        Button {
            isPasswordVisible.toggle()
        } label: {
            Image(systemName: isPasswordVisible ? "eye.slash.fill" : "eye.fill")
        }
        .padding(.trailing, 8)
    }
    .frame(height: 44)
    .frame(maxWidth: .infinity)
    .background(Color.gray.opacity(0.4))
    .cornerRadius(5)
    .padding(.horizontal)
}

}

Vahid
  • 3,352
  • 2
  • 34
  • 42