Los UITextField
son feos. Horrorosos. Muy pocas apps con un diseñador detrás usa los campos de texto por defecto.
En este tutorial te voy a enseñar como crear un «underlined» UITextField
como los que ves en la siguiente imagen. Un UITextField
personalizado, sin borders y con una línea debajo.
Únete a la newsletter para no perderte ningún nuevo tutorial: recibe un email cuando se publiquen nuevos artículos o vídeos y no pierdas la oportunidad de seguir aprendiendo.
Paso 1: Crear una subclase de UITextField
Abrimos Xcode y creamos una subclase de UITextField
. Ésta tendrá una propiedad privada que representará la línea inferior de subrayado (el underline), de tipo CALayer
:
class UnderlinedtextField: UITextField {
private let underline = CALayer()
}
Paso 2: Configurar la propiedad underline
Ahora vamos a configurar el estilo de la línea. Propiedades como su color o su grosor, así como su posición relativa al UITextField
. Para ello, nos creamos una función llamada setupUnderline()
.
private func setupUnderline() {
// 1
borderStyle = .none
// 2
let lineWidth: CGFloat = 1.0
underline.borderColor = UIColor.darkGray.cgColor
underline.frame = CGRect(
x: 0,
y: frame.size.height - lineWidth,
width: frame.size.width,
height: frame.size.height
)
underline.borderWidth = lineWidth
// 3
layer.addSublayer(underline)
layer.masksToBounds = true
}
¡Guau! Mucho código hay aquí. Vamos por partes:
// 1:
Borramos los horrorosos bordes que tienen losUITextField
por defecto.// 2:
Configuramos el estilo de la línea. Le asignamos un color, un grosor, y en dónde debe situarse.// 3:
Añadimos la línea a la pila de capas (layer stack)
layer.addSublayer(underline)
sólo añadirá una sola capa, ya que se trata siempre de la misma propiedadunderline
. Es decir, aunque este método se llamase 100 veces, sólo tendríamos una capa añadida.
Paso 3: Sobreescrir setNeedsLayout
Vamos a «sobreescribir» este método para decirle a la app que tiene que actualizar el layout por defecto de los UITextFields
. Técnicamente, si llamamos a este método se invalida el layout actual y avisa que se tiene que modificar durante el siguiente ciclo de actualización de la vista. Si quieres más información, échale un ojo a la documentación de UIKit
.
override func setNeedsLayout() {
super.setNeedsLayout()
setupUnderline()
}
Si ejecutamos la aplicación en estos momentos, veríamos algo así:
Paso 4: Modificar el intrinsicContentSize
Ahora mismo, la línea está muy cerca de lo que es el texto en sí. Cualquier diseñador te diría que los campos de texto «no respiran». Eso, traducido a nuestro idioma es que necesitamos añadir un poco de espacio entre la línea y el texto.
Hay muchas maneras de hacer esto, pero ya que estamos creando una subclase que puede ser utilizada tanto desde el InterfaceBuilder como por código, lo más limpio (en mi opinión) es modificar el intrinsicContentSize
de nuestra clase. Añade este código debajo de la propiedad underline
.
override var intrinsicContentSize: CGSize {
return CGSize(width: UIView.noIntrinsicMetric, height: 35.0)
}
Por defecto, la altura del
intrinsicContentSize
de unUITextField
es34
. Dado que el grosor de la línea es1
, como mínimo deberíamos añadir1
, de ahí el35
.
Si volvemos a ejecutar la aplicación, tu diseñador estaría algo más contento:
Pero claro, a los diseñadores les gusta que los componentes «respiren por todos los lados». Actualmente, sólo respira por abajo.
Paso 5: Añadir padding por los lados
Actualmente, si el usuario empieza a escribir el texto aparece inmediatamente encima de la línea, sin ningún margen interior. A los diseñadores esto tampoco les gusta, así que te exige que el texto «respire» también por los lados. Para ello, vamos a crear una función addPadding()
private func addPadding() {
// 1
rightViewMode = .always
leftViewMode = .always
// 2
let paddingView = UIView(
frame: CGRect(
x: 0,
y: 0,
width: 12,
height: 35
)
)
// 3
leftView = paddingView
rightView = paddingView
}
El padding consistirá simplemente en una vista vacía. Vayamos por partes:
// 1:
Todos losUITextFields
tienen un contenedor de vistas tanto a la izquierda como a la derecha. Tenemos que activar estos contenedores a través derightViewMode
yleftViewMode
, asignando su valor a.always
// 2:
Creamos una vista de 12px de ancho, y el mismo alto delUITextField
. Probablemente sería bueno extraer la altura en una constante.// 3:
Asignamos elpaddingView
a la vista de la izquierda y de la derecha.
Probablemente lo siguiente que haríamos todos (yo incluido) es llamar a esta función dentro de setNeedsLayout()
, justo después de setupUnderline()
. Si ejecutamos esta función dentro, provocaríamos un bucle infinito, ya que la super clase UIView
llama a setNeedsLayout()
por debajo cuando modificamos su layout, y eso es precisamente lo que estamos haciendo cuando utilizamos rightView
o leftView
.
Tenemos que ejecutar esta función desde otro sitio
Paso 6: Crear los inicializadores (init
s)
Debajo de la propiedad intrinsicContentSize
añade los métodos init
. Después de llamar a super, configuramos el padding:
override init(frame: CGRect) {
super.init(frame: frame)
addPadding()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
addPadding()
}
Si ejecutamos la aplicación, ahora se vería así:
Bonus: Ver el UnderlinedTextField
desde .xib
o Storyboards
Para utilizar el UnderlinedTextField
desde un fichero .xib
o un Storyboard, basta con añadir un UITextField
por defecto y cambiarle la clase. Sin embargo, en el Storyboard se verían los text fields por defecto. Y son feos. MUY feos.
Después de asignar la clase de todos los UITextField
como UnderlinedTextField
, volvemos al fichero .swift
y añadimos lo siguiente:
@IBDesignable
& prepareForInterfaceBuilder()
Para poder ver los estilos del text field personalizado en el InterfaceBuilder, debemos declararla como @IBDesignable
e implementar el método prepareForInterfaceBuilder()
, donde llamaremos a addPading()
y setupUnderline()
:
@IBDesignable
class UnderlinedtextField: UITextField {
...
...
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
addPadding()
setupUnderline()
}
}
Ahora el text field personalizado se verá en los Storyboards o .xib
s:
Conclusión
Crear tu propia subclase de UITextField
y poder utilizarla, tanto desde InterfaceBuilder como por código no es tan difícil. Por fin podrás deshacerte de los horribles text field nativos y utilizar los tuyos personalizados.
Si tienes alguna duda o sugerencia, escríbeme un comentario aquí abajo.
Por último, si te ha resultado útil te agradecería mucho que compartieras el post en tus redes sociales.