Pantalla de inicio de sesión con SecureField y Scroll
Resumen
¿Cómo programar una pantalla de inicio de sesión en Swift?
En el desarrollo de aplicaciones, especialmente en iOS, construir una pantalla de inicio de sesión es fundamental. Usamos varios tipos de vistas y stacks; además, incorporamos vistas como secure field y scroll, para asegurar una experiencia de usuario fluida. En este artículo, desglosamos paso a paso cómo lograrlo.
¿Cómo organizar las vistas dentro de nuestra aplicación?
Para comenzar a programar la pantalla de inicio de sesión, importa crear un diseño que acomode correctamente todos los elementos. Un VStack nos permite organizar elementos de manera vertical, facilitando la disposición:
Un Secure Field es similar a un TextField, pero oculta el texto que escribe el usuario, esencial para ingresar contraseñas. Usar un Secure Field es sencillo:
SecureField("Escribe tu contraseña", text: $contraseña)
Esto evita que se muestren los datos sensibles, mejorando así la seguridad de la aplicación. Se integra generalmente en un VStack junto a otros elementos como divisores:
VStack{SecureField("Escribe tu contraseña", text: $contraseña)Divider()}
¿Cómo integrar ScrollView para mejorar la usabilidad?
El uso de ScrollView es crucial cuando desarrollamos para dispositivos con pantallas más pequeñas. ScrollView permite al usuario desplazarse por la página, mostrando contenido adicional que de otro modo no cabría en pantalla:
ScrollView{VStack{Text("Iniciar sesión")// otros campos y botones}}
La idea es envolver el contenido del formulario dentro de un ScrollView para que el usuario pueda desplazarse verticalmente y acceder a todos los campos y botones sin problemas.
¿Cómo manejar los estilos y colores de manera profesional?
Para mantener un diseño profesional y consistente, empleamos colores de acuerdo a los estándares o guías de estilo de la aplicación. Se pueden definir colores personalizados en Assets.xcassets:
Cree un nuevo Color Set y configure su valor en hexadecimal.
Asigne nombres claros y significativos, por ejemplo, darkCian.
De esta manera, se garantiza que los colores se gestionen centralizadamente y se mantenga la coherencia visual a lo largo de la aplicación.
Integrar estas prácticas en el desarrollo de tu aplicación iOS no solo mejora la experiencia del usuario, sino que también optimiza la funcionalidad y accesibilidad. Sigue practicando y expandiendo tu conocimiento en SwiftUI y pronto desarrollarás aplicaciones más sofisticadas. ¡Adelante!
En la sección de los botones Iniciar Sesión y Regístrate, yo preferí quitar los Spacer a lado y lado de los botones y mejor poner un padding horizontal de 30 al contenedor HStack. Igual que hicimos con el VStack de InicioSesionView.
De esta forma queda más parecido al diseño original, no tan apretado todo el contenido.
(
Yo recomiendo para los placeholders crear una extensión de View y agregar el metodo placeholder
extension View{ func placeholder<Content:View>( when shouldShow:Bool,alignment:Alignment=.leading, @ViewBuilder placeholder:()->Content)-> some View{ZStack(alignment: alignment){placeholder().opacity(shouldShow ?1:0) self
}}}
Que luego podemos utilizar de esta manera, para que quede el código más limpio y más legible
Cuando un color va ser igual tanto para el modo light como para el modo dark, puedes colocar en el inspector en la parte de Appearances en un valor "None"
Hice este componente para reutilizar los estilos de los inputs de esta pantalla:
struct GameStreamAuthInput<Content:View>:View{letinput:()->Contentlettitle:StringletplaceholderText:StringletshowPlaceholder:Boolinit(title:String,placeholderText:String,showPlaceholder:Bool,aligment:Alignment=.leading,input: @escaping()->Content){ self.input= input
self.title= title
self.placeholderText= placeholderText
self.showPlaceholder= showPlaceholder
}varbody: some View{Text(title).foregroundColor(Color("dark_cyan"))ZStack(alignment:.leading){input().placeholder(when: self.showPlaceholder){Text(self.placeholderText).font(.caption).foregroundColor(.gray)}}Divider().frame(height:1).background(Color("dark_cyan")).padding(.bottom)}}
inclusive usando .foregroundColor(.gray), el correo electronico se transorma en azul
Me pasó lo mismo y pasé un buen rato tratando de comprender por qué pasaba hasta que descubrí que se pone en Azul porque es identificado como un link hacia un correo, entonces predeterminadamente los links siempre se pintan de azul.
La solución que encontré fue esta:
Efectivamente como lo menciona devsptl25332, esto sucede porque swift intenta generar un enlace automáticamente y le aplica un accent color blue por defecto (este accent color por defecto también lo puedes modificar si se requiere).
Para solucionar esto implementa un Text con el argument verbatim, de esta forma swift plasmara el string literal que le estamos indicando al struct Text:
Recomendaria siempre revisar la documentación directamente aqui).
Si no te cambia el color del correo este puede ser una opción:
Yo le agregué el toggle para quitar el máscara de la contraseña. No es el código más lindo pero es trabajo honesto xD
@Statevar correo =""@Statevar contrasena =""@StatevarisSecured:Bool=truevarbody: some View{ScrollView{VStack(alignment:.leading){Text("Correo electrónico").bold().foregroundColor(Color(red:0.25,green:0.79,blue:0.63,opacity:1.0))ZStack(alignment:.leading){if correo.isEmpty{Text(verbatim:"ejemplo@gmail.com").font(.caption).foregroundColor(.gray)}TextField("",text: $correo).foregroundColor(.white)}Divider().frame(height:1).background(Color(red:0.25,green:0.79,blue:0.63,opacity:1.0)).padding(.bottom)HStack(){ZStack(alignment:.leading){Group{if isSecured{if contrasena.isEmpty{Text(verbatim:"Escribe tu contraseña").font(.caption).foregroundColor(.gray)}SecureField("",text: $contrasena).foregroundColor(.white)}else{TextField("",text: $contrasena).foregroundColor(.white)}}}Button(action:{ isSecured.toggle()}){Image(systemName: self.isSecured?"eye.slash":"eye").accentColor(.gray)}}Divider().frame(height:1).background(Color(red:0.25,green:0.79,blue:0.63,opacity:1.0)).padding(.bottom)}.padding(.horizontal,80)}}}
Y aquí se ve funcionando:
Contraseña súper segura :v
Yo decidí usar TextFields y separar cada campo del formulario en un componente Form:
struct Login:View{ @Statevar email =String() @Statevar password =String()varbody: some View{ScrollView{VStack(alignment:.leading){Form(label:"Correo electrónico",placeholder:"usuario@ejemplo.com",value: $email)Divider().frame(height:1)Form(label:"Contraseña",placeholder:"4%C5Pj*^6*&8",value: $password)}}// .background(Color("background"))}}struct Form:View{letlabel:Stringletplaceholder:Stringvarvalue:Binding<String>// para leer el valor usar la propiedad .wrappedValuevarbody: some View{Text(label).foregroundStyle(Color("darkcyan")).bold()TextField(text: value){Text(placeholder).foregroundColor(.gray)}.foregroundColor(.white).bold()Divider().frame(height:1).background(Color("darkcyan"))}}
Como complemento a la extencion aportada por Omar, yo crearia otra extencion de View para implementar el TextField completo
extension View{ func customize( when shouldShow:Bool,hint:String,title:String)-> some View{VStack(alignment:.leading){Text(title).foregroundColor(Color("dark-cyan")).padding(.bottom,-4.0)ZStack(alignment:.leading){Text(hint).font(.caption).foregroundColor(.gray).opacity(shouldShow ?1:0).padding(.leading,4.0) self
}Divider().frame(height:1).background(Color("dark-cyan"))}}}