DEV Community

GoyesDev
GoyesDev

Posted on

SwiftUI #27: TextField

Un TextField permite al usuario insertar una línea de texto.

  • init(_:text:). titleKey es la llave del texto localizado que será usado como "placeholder". text es un binding a una propiedad de tipo String que almacenará el valor insertado por el usuario.
  • textFieldStyle(_:): Define el estilo para los TextFields almacenados en esta vista. El argumento debe conformar el protocolo TextFieldStyle. Existe algunas estructuras por defecto: automatic, plain, roundedBorder, squareBorder.
  • autocorrectionDisabled(_:)
  • textInputAutocapitalization(_:). El argumento es una estructura que puede ser characteres, never, sentences (por defecto) y words.
  • keyboardType(_:). El argumento (UIKeyboardType) es una enumeración con valores default, asciiCapable, numbersAndPunctuation, URL, numberPad, phonePad, namePhonePad, emailAddress, decimalPad, asciiCapableNumberPad y alphabet.
  • onSubmit(of:_:). Ejecuta una acción cuando el SubmitTriggers (e.g. botón "Done" o "Return" del teclado) se dispara.
  • submitLabel(_:). Especifica la etiqueta (de tipo SubmitLabel) usada para el botón "Done" del teclado virtual. Esta puede ser continue, done, go, join, next, return, route, search y send.
  • submitScope(_:). Evita la emisión de un evento "submit" a una vista más alta en la jerarquía.
struct ContentView: View {
  @State private var title = "Default title"
  @State private var titleInput = ""
  var body: some View {
    VStack {
      Text(title)
        .lineLimit(1)
        .padding()
        .background(.yellow)

      TextField("Inserte el nuevo título", text: $titleInput)
        .textFieldStyle(.roundedBorder)
        .textInputAutocapitalization(.words)
        .submitLabel(.continue)
        .onSubmit {
          updateTitle()
        }

      Button("Actualizar") {
        updateTitle()
      }
    }
  }

  private func updateTitle() {
    title = titleInput
    titleInput = ""
  }
}
Enter fullscreen mode Exit fullscreen mode

Manejo del foco

Cuando una vista que puede recibir una entrada o procesar feedback del usuario es seleccionada, se dice que tiene "foco".

Se puede procesar cuando la vista gane el foco, determinar si el foco está en cierta vista o quitar el foco de ella. Para ello se usan los property wrappers:

  • @FocusState: Almacena el valor que determina dónde está el foco en un momento determinado.
  • @FocusedBinding. Se usa para pasar el estado del foco a otras vistas.

Se pueden usar los siguientes modificadores:

  • focused(_:equals:). Almacena el estado actual del foco en un @FocusState. El argumento value es el valor Hashable que identifica a la vista con foco.
  • focusable(_:). Determina si se puede enfocar esta vista.
struct LoginForm: View {
  enum Field: Hashable {
    case username
    case password
  }

  @State private var username = ""
  @State private var password = ""
// El valor inicial de @FocusState es nil
// indicando que no hay ninguna vista enfocada
  @FocusState private var focusedField: Field?

  var body: some View {
    Form {
      TextField("Username", text: $username)
        .focused($focusedField, equals: .username)

      SecureField("Password", text: Binding(
        get: { password },
        set: { newValue in
          password = String(newValue.prefix(10))
        }
      ))
        .focused($focusedField, equals: .password)
        .onChange(of: password, initial: false) {
          if password.count > 8 {
            print("onChange es para reaccionar, no para corregir")
            print("Si modifico password, voy a crear un bucle interno")
            print("Si quiero cortar los caracteres a partir de un umbral")
            print("Puedo usar el binding de arriba")
          }
        }

      Button("Sign In") {
        username = username.trimmingCharacters(in: .whitespaces)
        password = password.trimmingCharacters(in: .whitespaces)

        if username.isEmpty {
          focusedField = .username
        } else if password.isEmpty {
          focusedField = .password
        } else {
          // handleLogin(username, password)
          focusedField = nil // Esto cierra el teclado
        }
      }
      .disabled( username.isEmpty || password.isEmpty)
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Para ocultar el teclado programáticamente, hay que fijar en nil la propiedad @FocusState.

Preprocesar el estado de los campos de texto

Es de nuestro interés eliminar los espacios antes y después del texto insertado por el usuario. Para ello, conviene usar el método trimmingCharacters(in:).

Deshabilitar el botón

Si no se cumplen las condiciones para procesar el formulario, se puede deshabilitar el botón para enviarlo con disabled(_:).

Observar una propiedad desde una vista

Se puede inspeccionar directamente el cambio de una propiedad con el modificador onChange(of:initial:_:) que ejecuta action cuando value cambia. initial indica si la acción debe ejecutarse también cuando la vista aparece en pantalla.

Campo de texto multilínea

Por defecto, un campo de texto tiene una sola línea. Sin embargo, se puede hacer de varias. Para ello se usa:

  • lineLimit(_:). Recibe un solo valor que define el número de líneas que va a tener el campo.
  • lineLimit(_:). Recibe un rango con el número mínimo y máximo de líneas que tendrá el campo de texto.
  • init(_:text:axis:). axis es el eje sobre el que se hace scroll.
struct ContentView: View {

  @State private var username = ""
  @State private var name= ""

  var body: some View {
    TextField("Username", text: $username, axis: .vertical)
      .padding()
      .lineLimit(5)

    TextField("Name", text: $name, axis: .vertical)
      .padding()
      .lineLimit(3...5)
  }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)