Introducción al curso

1

Construyamos una app para iOS

2

Introducción a la arquitectura MVVM

3

Planeando nuestra app

Creando las primeras pantallas de la app

4

Programando la primera pantalla en módulos

5

Escribiendo la lógica para mostrar dos pantallas

6

Pantalla de inicio de sesión con SecureField y Scroll

7

Completando nuestra pantalla de inicio de sesión

8

Pantalla de registro de usuario

9

Comprobando el funcionamiento de nuestras pantallas

10

Estructura de las pantallas con TabView

11

Creando nuestra pantalla home

12

Pantalla home: logo y barra de búsqueda

13

Pantalla home: programación de interfaces estáticas

14

Pantalla home: carruseles

Aplicando arquitectura MVVM

15

Creando estructura para arquitectura MVVM

16

Modelando nuestro JSON

17

Peticiones al servidor

18

Mostrar información de un servidor de manera dinámica

19

Mostrar imágenes de forma dinámica y eficiente con LazyVGrid

Reproductor y búsqueda de video

20

Pasar datos entre pantallas

21

Darle datos de inicio a un Canvas

22

Reproducir videos dinámicamente de un servidor

23

Mostrar imágenes dinámicamente de un servidor

24

Mostrar alertas

25

Programar clase de búsqueda

26

Programar método de búsqueda

Últimas pantallas de la app

27

Pantalla de favoritos

28

Pantalla de perfil de usuario

29

Módulo de ajustes de perfil con Toggle

30

Pantalla de edición de perfil

31

Módulo de edición de perfil

32

Guardado interno de datos

Utilizando la cámara y fotos del iPhone

33

Captura de foto de perfil: ImagePicker y vista Sheet

34

Captura de foto de perfil con la cámara: modificar librerías de terceros

35

Captura de foto de perfil con la cámara: recuperar imágenes guardadas

¿Qué más posibilidades tiene SwiftUI?

36

Mejoremos nuestra app

No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Pantalla de inicio de sesión con SecureField y Scroll

6/36
Recursos

Aportes 14

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Si en el placeholder ([email protected]) no te agarra el color puedes hacer esto:

Text(verbatim: "[email protected]").font(.caption).foregroundColor(.gray)

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

TextField("", text: $email).placeholder(when: email.isEmpty) {              				 
      Text("[email protected]").font(.caption).foregroundColor(.gray)
}

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 {
    let input: () -> Content
    let title: String
    let placeholderText: String
    let showPlaceholder: Bool
    
    init(
        title: String,
        placeholderText: String,
        showPlaceholder: Bool,
        aligment: Alignment = .leading,
        input: @escaping () -> Content
    ) {
        self.input = input
        self.title = title
        self.placeholderText = placeholderText
        self.showPlaceholder = showPlaceholder
    }
    var body: 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)
    }
}

Y en la pantalla de log in:

                GameStreamAuthInput(
                    title: "Correo electrónico",
                    placeholderText: "[email protected]",
                    showPlaceholder: email.isEmpty
                ) {
                    TextField(
                        "",
                        text: $email
                    )
                }
                GameStreamAuthInput(
                    title: "Contraseña",
                    placeholderText: "********",
                    showPlaceholder: password.isEmpty
                ) {
                    SecureField(
                        "",
                        text: $password
                    )
                }

Para Swift 14 creo que la forma correcta de agregar un placeholder custom sería esto:

TextField(
text: $yourProperty,
label: {
Text(“your label value”).foregroundColor(your color)
})

Esto evita usar un ZStack

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

@State var correo = ""
@State var contrasena = ""
@State var isSecured: Bool = true

var body: 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: "[email protected]").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 {
    @State var email = String()
    @State var password = String()
    
    var body: some View {
        ScrollView {
            VStack(alignment: .leading) {
                Form(label: "Correo electrónico", placeholder: "[email protected]", value: $email)
                Divider()
                    .frame(height: 1)
                Form(label: "Contraseña", placeholder: "4%C5Pj*^6*&8", value: $password)
            }
        }
//        .background(Color("background"))
    }
}

struct Form: View {
    let label: String
    let placeholder: String
    var value: Binding<String> // para leer el valor usar la propiedad .wrappedValue
    
    var body: 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"))
        }
    }
    
}

Y se utlizaria desde asi:

<code> 
 TextField("", text: $email).customize(when: email.isEmpty, hint: "julianmp0", title: "Correo Electrónico")
Si no te cambia el color del correo este puede ser una opción: ```js Text("[email protected]").font(.caption).tint(.gray) ```
En xcode 15 se puede hacer diferente y todo con los TextField `VStack(alignment: .leading){` `Text("Correo electrónico")` `.foregroundColor(.colorCian)` `TextField("",` `text: $email,` `prompt: Text("Ingresa tu email").foregroundColor(.gray)` `).foregroundColor(.white)` `Divider()` `.frame(height: 1, alignment: .center)` `.background(.colorDarkCian)` `.padding(.bottom)` `}`
En xcode 15 los colores que creamos en Color Set los podemos llamar con .name ej: `.foregroundColor(.ColorDarkCian)`

les ahorro todo el parrafo de codigo para hacer el textfield con placeholder

TextField("", text: $correo, prompt: Text(verbatim:"[email protected]").foregroundColor(Color(white:0.7).foregroundColor(.white).tint(Color("Dark-Cyan"))

basicamente el prompt permite cambiar el placeholder pasando un text pueden hacer los cambios que requieran

el verbatim evita que iOS detecte links y lo tome como string literal

y el tint es para cambiar el color del cursor, ya que siempre lo muestra azul y no cuadra con el tema de la aplicacion, asi que lo deje en dark cyan