UITextfield leftView / rightView padding en iOS7


94

Las vistas leftView y rightView de un UITextField en iOS7 están muy cerca del borde del campo de texto.

¿Cómo puedo agregar algo de relleno (horizontal) a esos elementos?

Intenté modificar el marco, pero no funcionó.

uint padding = 10;//padding for iOS7
UIImageView * iconImageView = [[UIImageView alloc] initWithImage:iconImage];    
iconImageView.frame = CGRectMake(0 + padding, 0, 16, 16);
textField.leftView = iconImageView;

Tenga en cuenta que no me interesa agregar relleno al texto del campo de texto, como este Establecer relleno para UITextField con UITextBorderStyleNone


posible duplicado de inserción
Zorayr

1
No, esto es una pregunta sobre cómo sangrar la imagen que se muestra como leftView en un campo de texto. Sin sangrar el texto en sí. Pruebe su código y verá que la configuración de leftView en una imagen coloca esa imagen contra el borde izquierdo del campo de texto, sin relleno. Se ve feo.
piedra

Respuestas:


90

Estaba trabajando en esto yo mismo y usé esta solución:

- (CGRect) rightViewRectForBounds:(CGRect)bounds {

    CGRect textRect = [super rightViewRectForBounds:bounds];
    textRect.origin.x -= 10;
    return textRect;
}

Esto moverá la imagen de la derecha en 10 en lugar de apretar la imagen contra el borde en iOS 7.

Además, esto estaba en una subclase de UITextField, que puede crearse mediante:

  1. Cree un nuevo archivo que sea una subclase de en UITextFieldlugar del predeterminadoNSObject
  2. Agregue un nuevo método llamado - (id)initWithCoder:(NSCoder*)coderpara configurar la imagen

    - (id)initWithCoder:(NSCoder*)coder {
        self = [super initWithCoder:coder];
    
        if (self) {
    
            self.clipsToBounds = YES;
            [self setRightViewMode:UITextFieldViewModeUnlessEditing];
    
            self.leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"textfield_edit_icon.png"]];
        }
    
        return self;
    }
  3. Puede que tengas que importar #import <QuartzCore/QuartzCore.h>

  4. Agrega el rightViewRectForBoundsmétodo anterior

  5. En Interface Builder, haga clic en el TextField que le gustaría subclase y cambie el atributo de clase al nombre de esta nueva subclase


¿Cómo usar IBDesignable para esto mismo?
riddhi

para obtener la última versión o si está viendo esto en 2020. visite: stackoverflow.com/a/55041786/6596443
AKINNUBI ABIOLA SYLVESTER

167

Una solución mucho más sencilla, que aprovecha contentMode:

    arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"down_arrow"]];
    arrow.frame = CGRectMake(0.0, 0.0, arrow.image.size.width+10.0, arrow.image.size.height);
    arrow.contentMode = UIViewContentModeCenter;

    textField.rightView = arrow;
    textField.rightViewMode = UITextFieldViewModeAlways;

En Swift 3,

    let arrow = UIImageView(image: UIImage(named: "arrowDrop"))
    if let size = arrow.image?.size {
        arrow.frame = CGRect(x: 0.0, y: 0.0, width: size.width + 10.0, height: size.height)
    }
    arrow.contentMode = UIViewContentMode.center
    self.textField.rightView = arrow
    self.textField.rightViewMode = UITextFieldViewMode.always

1
También puede usar ScaleAspectFit en lugar del centro ... si el tamaño de la imagen no coincide con el marco exacto.
Mihir Mehta

Usé su ejemplo para UIButton (en lugar de UIImageView) mientras que su tipo es InfoLight.
OhadM

Descubrí que ".right" en lugar de ".center" hace que se parezca más a una barra de búsqueda incorporada, como la de la aplicación Contactos. Gran solución en esto, gracias por publicarlo.
James Toomey

O si necesita ser preciso en la recreación del diseño, coloque la imagen a la izquierda y luego aumente el ancho para lograr un relleno exacto
jovanjovanovic

4
Esto parece no funcionar más con iOS 13 y Xcode 11 Beta 7. Sin embargo, funciona bien en iOS 11/12.
PatrickDotStar

49

La forma más fácil es agregar un UIView a leftView / righView y agregar un ImageView a UIView, ajustar el origen de ImageView dentro de UIView en cualquier lugar que desee, esto funcionó para mí como un encanto. Solo necesita unas pocas líneas de código

UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 5, 26, 26)];
imgView.image = [UIImage imageNamed:@"img.png"];

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
[paddingView addSubview:imgView];
[txtField setLeftViewMode:UITextFieldViewModeAlways];
[txtField setLeftView:paddingView];

UIViewContentMode ¡No funciona, pero esta respuesta funciona como un encanto!
nigong

14

Esto funciona muy bien para Swift:

let imageView = UIImageView(image: UIImage(named: "image.png"))
imageView.contentMode = UIViewContentMode.Center
imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 20.0, imageView.image!.size.height)
textField.rightViewMode = UITextFieldViewMode.Always
textField.rightView = imageView

no se puede convertir el valor del tipo 'cadena' al tipo de argumento esperado 'UIImage? "

7

Esto funciona para mi

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 20)];
self.passwordTF.leftView = paddingView;
self.passwordTF.leftViewMode = UITextFieldViewModeAlways;

Que te ayude.


6

Me gusta esta solución porque resuelve el problema con una sola línea de código.

myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(10.0f, 0.0f, 0.0f);

Nota: .. o 2 si considera incluir QuartzCore en una línea :)


1
Esto también mueve la frontera
Softlion

1
pero no resuelve el problema con el relleno derecho solo el problema del relleno izquierdo
carmen_munich

1
Tuve un mejor resultado usando rightView.layer.sublayerTransform = CATransform3DMakeTranslation (-10.0f, 0.0f, 0.0f), pero +1 para el método
Thibaud David

Tenga en cuenta que esto también desplazará el botón "borrar" del campo de texto hacia la derecha, lo que puede empujarlo más allá del borde del campo de texto. Si no necesita el botón de borrar, este es un gran enfoque; de ​​lo contrario, tal vez no.
Tom Harrington

4

La mejor manera de hacer esto es simplemente crear una clase usando la subclase de UITextField y en el archivo .m

  #import "CustomTextField.h"
  #import <QuartzCore/QuartzCore.h>
  @implementation CustomTextField


- (id)initWithCoder:(NSCoder*)coder 
 {
self = [super initWithCoder:coder];

if (self) {

    //self.clipsToBounds = YES;
    //[self setRightViewMode:UITextFieldViewModeUnlessEditing];

    self.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,15,46)];
    self.leftViewMode=UITextFieldViewModeAlways;
      }

return self;

}

al hacer esto, vaya a su guión gráfico o xib y haga clic en el inspector de identidad y reemplace UITextfield con su propia opción "CustomTextField" en la clase.

Nota: Si simplemente proporciona relleno con diseño automático para el campo de texto, su aplicación no se ejecutará y solo mostrará una pantalla en blanco.


4

En lugar de manipular imageView o image, podemos anular un método proporcionado por apple para rightView.

class CustomTextField : UITextField { 

override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
    let offset = 5
    let width  = 20
    let height = width
    let x = Int(bounds.width) - width - offset
    let y = offset
    let rightViewBounds = CGRect(x: x, y: y, width: width, height: height)
    return rightViewBounds
}}

y de la misma manera podemos anular la función de abajo para la vista izquierda.

override func leftViewRect(forBounds bounds: CGRect) -> CGRect {
    /*return as per requirement*/

}

3

Encontré esto en alguna parte ...

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
paddingView.backgroundColor = [UIColor clearColor];
itemDescription.leftView = paddingView;
itemDescription.leftViewMode = UITextFieldViewModeAlways;

[self addSubview:itemDescription];

4
Eso solo agrega relleno al texto, que no es lo que busca el autor de la pregunta. No quiere una vista izquierda clara. Quiere que se muestre una imagen como leftView.
piedra

Simplemente puede agregar la imagen en paddingView.
Matheus Weber

3

Rápido 5

class CustomTextField: UITextField {
    func invalidate() {
        let errorImage =  UIImageView(image: UIImage(named: "errorImage"))
        errorImage.frame = CGRect(x: 8, y: 8, width: 16, height: 16)
        rightView = UIView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
        rightView?.addSubview(errorImage)
        rightViewMode = .always
    }
}

Querrás:

  • Subclase UITextField
  • Escriba un método de invalidación dentro del campo de texto subclasificado
  • En el método invalidar, cree una UIView imagen más grande que su
  • Coloque su imagen dentro de la vista
  • Asignar la vista a UITextField.rightView

2

Aquí hay una solución:

 UIView *paddingTxtfieldView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 42)]; // what ever you want 
 txtfield.leftView = paddingTxtfieldView;
 txtfield.leftViewMode = UITextFieldViewModeAlways;

1

Cree una clase UITextField personalizada y use esa clase en lugar de UITextField. Override - (CGRect) textRectForBounds: (CGRect) límites para establecer el rect que necesita

Ejemplo

- (CGRect)textRectForBounds:(CGRect)bounds{
     CGRect textRect = [super textRectForBounds:bounds];
     textRect.origin.x += 10;
     textRect.size.width -= 10;
     return textRect;
}

1

El siguiente ejemplo es para agregar relleno horizontal a una vista izquierda que resulta ser un icono; puede usar un enfoque similar para agregar relleno a cualquiera UIViewque le gustaría usar como vista izquierda del campo de texto.

Dentro de la UITextFieldsubclase:

static CGFloat const kLeftViewHorizontalPadding = 10.0f;

@implementation TextFieldWithLeftIcon
{
  UIImage *_image;
  UIImageView *_imageView;
}

- (instancetype)initWithFrame:(CGRect)frame image:(UIImage *)image
{
  self = [super initWithFrame:frame];
  if (self) {
    if (image) {
      _image = image;
      _imageView = [[UIImageView alloc] initWithImage:image];
      _imageView.contentMode = UIViewContentModeCenter;
      self.leftViewMode = UITextFieldViewModeAlways;
      self.leftView = _imageView;
    }
  }
  return self;
}

#pragma mark - Layout 

- (CGRect)leftViewRectForBounds:(CGRect)bounds
{
  CGFloat widthWithPadding = _image.size.width + kLeftViewHorizontalPadding * 2.0f;
  return CGRectMake(0, 0, widthWithPadding, CGRectGetHeight(bounds));
}

Aunque somos una subclase UITextField aquí, creo que este es el enfoque más limpio.


1
- (CGRect)rightViewRectForBounds:(CGRect)bounds
{
    return CGRectMake(bounds.size.width - 40, 0, 40, bounds.size.height);
}

Si UITextFieldestá incrustado en a UISearchBar, ¿cómo le dice UISearchBarque use su UITextFieldsubclase?
crishoj

1

gracias chicos por sus respuestas, para mi sorpresa, ninguno de ellos realmente encajó la imagen de la vista correcta en mi campo de texto sin dejar de proporcionar el relleno necesario. luego pensé en usar el modo AspectFill y sucedieron milagros. para futuros buscadores, esto es lo que usé:

UIImageView *emailRightView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 35, 35)];
emailRightView.contentMode = UIViewContentModeScaleAspectFill;
emailRightView.image = [UIImage imageNamed:@"icon_email.png"];
emailTextfield.rightViewMode = UITextFieldViewModeAlways;
emailTextfield.rightView = emailRightView;

el 35 en el marco de mi vista de imagen representa la altura de mi campo de texto de correo electrónico, no dude en ajustarlo a sus necesidades.


1

Yo mismo he tenido este problema y, con mucho, la solución más fácil es modificar su imagen para simplemente agregar relleno a cada lado de la imagen.

Acabo de modificar mi imagen png para agregar un relleno transparente de 10 píxeles, y funciona bien, ¡sin codificación alguna!


1

Si está usando un UIImageView como leftView, entonces debe usar este código:

Precaución: No use viewWillAppear interior o viewDidAppear

-(UIView*)paddingViewWithImage:(UIImageView*)imageView andPadding:(float)padding
{
    float height = CGRectGetHeight(imageView.frame);
    float width =  CGRectGetWidth(imageView.frame) + padding;

    UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];

    [paddingView addSubview:imageView];

    return paddingView;
}

1

Creé un método personalizado en mi clase ViewController, como se muestra a continuación:

- (void) modifyTextField:(UITextField *)textField
{
    // Prepare the imageView with the required image
    uint padding = 10;//padding for iOS7
    UIImageView * iconImageView = [[UIImageView alloc] initWithImage:iconImage];    
    iconImageView.frame = CGRectMake(0 + padding, 0, 16, 16);

    // Set the imageView to the left of the given text field.
    textField.leftView = iconImageView;
    textField.leftViewMode = UITextFieldViewModeAlways;
}

Ahora puedo llamar a ese método dentro de ( viewDidLoadmétodo) y enviar cualquiera de mis TextFieldsa ese método y agregar relleno tanto para la derecha como para la izquierda, y dar texto y colores de fondo escribiendo solo una línea de código, de la siguiente manera:

[self modifyTextField:self.firstNameTxtFld];

¡Esto funcionó perfectamente en iOS 7! ¡Espero que esto también funcione en iOS 8 y 9 también!

Sé que agregar demasiadas vistas puede hacer que este objeto sea un poco más pesado para cargar. Pero cuando me preocupaba la dificultad en otras soluciones, me encontré más predispuesto a este método y más flexible al usarlo. ;)

Espero que esta respuesta pueda ser útil o útil para encontrar otra solución para otra persona.

¡Salud!


1

Esto funciona para mí al igual que busco:

func addImageViewInsideMyTextField() {
    let someView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 24))
    let imageView = UIImageView(image: UIImage(named: "accountImage"))
    imageView.frame = CGRect(x: 16, y: 0, width: 24, height: 24)
    imageView.contentMode = .scaleAspectFit
    someView.addSubview(imageView)

    self.myTextField.leftView = someView
    self.myTextField.leftViewMode = .always
}

1

Desde iOS 13 y Xcode 11, esta es la única solución que nos funciona.

// Init of custom UITextField
override init(frame: CGRect) {
    super.init(frame: frame)

    if let size = myButton.imageView?.image?.size {
        myButton.frame = CGRect(x:0, y: 0, width: size.width, height: size.height)

        let padding: CGFloat = 5
        let container = UIView(frame: CGRect(x:0, y: 0, width: size.width + padding, height: size.height))
        container.addSubview(myButton)

        myButton.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            myButton.topAnchor.constraint(equalTo: container.topAnchor),
            myButton.leftAnchor.constraint(equalTo: container.leftAnchor),
            myButton.bottomAnchor.constraint(equalTo: container.bottomAnchor),
            myButton.rightAnchor.constraint(equalTo: container.rightAnchor, constant: -padding),
        ])

        textField.rightViewMode = .always
        textField.rightView = container
    }
}

las respuestas anteriores no funcionan para mí, esta funciona.
Mark Dylan B Mercado

1

// Establecer vista derecha de UITextField, swift 4.2TxtPass.rightViewMode = UITextField.ViewMode.always let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 18, height: 18)) imageView.contentMode = UIView.ContentMode.scaleAspectFit let image = UIImage(named: "hidepass") imageView.image = image let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 28, height: 18)) rightView.addSubview(imageView) rightView.contentMode = UIView.ContentMode.left TxtPass.rightView = rightView


0

Un truco: agregue un UIView que contenga UIImageView a UITextField como rightView. Este UIView debe ser de mayor tamaño, ahora coloque el UIImageView a la izquierda. Entonces habrá un relleno de espacio desde la derecha.

// Add a UIImageView to UIView and now this UIView to UITextField - txtFieldDate
UIView *viewRightIntxtFieldDate = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 30)]; 
// (Height of UITextField is 30px so height of viewRightIntxtFieldDate = 30px)
UIImageView *imgViewCalendar = [[UIImageView alloc] initWithFrame:CGRectMake(0, 10, 10, 10)];
[imgViewCalendar setImage:[UIImage imageNamed:@"calendar_icon.png"]];
[viewRightIntxtFieldDate addSubview:imgViewCalendar];
txtFieldDate.rightViewMode = UITextFieldViewModeAlways;
txtFieldDate.rightView = viewRightIntxtFieldDate;

0

La forma más fácil es simplemente cambiar el campo de texto como RoundRect en lugar de personalizado y ver la magia. :)


0

para Swift2, uso

...
        self.mSearchTextField.leftViewMode = UITextFieldViewMode.Always
        let searchImg = UIImageView(image: UIImage(named: "search.png"))
        let size = self.mSearchTextField.frame.height
        searchImg.frame = CGRectMake(0, 0, size,size)
        searchImg.contentMode = UIViewContentMode.ScaleAspectFit
        self.mSearchTextField.leftView = searchImg
...

0
...
textField.rightView = UIImageView(image: ...)
textField.rightView?.contentMode = .top
textField.rightView?.bounds.size.height += 10
textField.rightViewMode = .always
...

0

Enfoque simple:

textField.rightViewMode = .always
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 25, height: 15))
textField.contentMode = .scaleAspectFit
imageView = UIImage(named: "imageName")
textField.rightView = imageView

Nota: La altura debe ser menor que el ancho para permitir un acolchado horizontal.


0

Me doy cuenta de que esta es una publicación antigua y esta respuesta es un poco específica para mi caso de uso, pero la publiqué en caso de que otros busquen una solución similar. Quiero mover leftView o rightView de UITextField pero no estoy poniendo imágenes en ellos y no quiero constantes codificadas.

Mi interfaz de usuario pide ocultar el botón de borrar del campo de texto y mostrar un UIActivityIndicatorView donde se encontraba el botón de borrar.

Agregué una ruleta al rightView, pero fuera de la caja (en iOS 13) se desplazó 20 píxeles a la derecha del clearButton. No me gusta usar números mágicos ya que la posición de clearButton y rightView están sujetos a cambios en cualquier momento por parte de Apple. La intención del diseño de la interfaz de usuario es "ruleta donde está el botón de borrar", por lo que mi solución fue subclase UITextField y anular rightViewRect(forBounds).

override func rightViewRect(forBounds bounds: CGRect) -> CGRect {

    // Use clearButton's rectangle
    return self.clearButtonRect(forBounds: bounds)
}

A continuación se muestra un ejemplo de trabajo (sans Storyboard):

//------------------------------------------------------------------------------
class myCustomTextField: UITextField {

    override func rightViewRect(forBounds bounds: CGRect) -> CGRect {

        // Use clearButton rectangle
        return self.clearButtonRect(forBounds: bounds)
    }
}

//------------------------------------------------------------------------------
class myViewController: UIViewController {

    var activityView: UIActivityIndicatorView = {
        let activity = UIActivityIndicatorView()
        activity.startAnimating()
        return activity
    }()

    @IBOutlet weak var searchTextField: myCustomTextField!

    //------------------------------------------------------------------------------
    // MARK: - Lifecycle
    //------------------------------------------------------------------------------
    override func viewDidLoad() {

        super.viewDidLoad()

        searchTextField.rightView = activityView
        searchTextField.rightViewMode = .never // Hide spinner
        searchTextField.clearButtonMode = .never // Hide clear button

        setupUIForTextEntry()
    }

    // ...
    // More code to switch between user text entry and "search progress" 
    // by calling setupUI... functions below
    // ...

    //------------------------------------------------------------------------------
    // MARK: - UI
    //------------------------------------------------------------------------------
    func setupUIForTextEntry() {

        // Hide spinner
        searchTextField.rightViewMode = .never

        // Show clear button
        searchTextField.clearButtonMode = .whileEditing
        searchTextField.becomeFirstResponder()
    }

    //------------------------------------------------------------------------------
    func setupUIForSearching() {

        // Show spinner
        searchTextField.rightViewMode = .always

        // Hide clear button
        searchTextField.clearButtonMode = .never
        searchTextField.resignFirstResponder()
    }

    //------------------------------------------------------------------------------

}

//------------------------------------------------------------------------------
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.