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

bajo cero
fuente
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

AngeloS
fuente
¿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
TTillage
fuente
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];
vishal dharankar
fuente
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
Andy
fuente
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.

Ashu
fuente
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 :)

Jordi Corominas
fuente
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.

Anuj Kumar Rai
fuente
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*/

}
Pranav Gupta
fuente
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];
Expresión regular
fuente
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
bkSwifty
fuente
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;
Dev Patel
fuente
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;
}
Kedar
fuente
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.

Zorayr
fuente
1
- (CGRect)rightViewRectForBounds:(CGRect)bounds
{
    return CGRectMake(bounds.size.width - 40, 0, 40, bounds.size.height);
}
carmen_munich
fuente
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.

carlos16196
fuente
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!

Ricardo
fuente
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;
}
Zeeshan
fuente
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!

Randika Vishman
fuente
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
}
Aleksandr Skorotkin
fuente
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
    }
}
PatrickDotStar
fuente
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

NSurajit
fuente
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;
Suraj Mirajkar
fuente
0

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

Shilpa
fuente
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
...
Haiyuan
fuente
0
...
textField.rightView = UIImageView(image: ...)
textField.rightView?.contentMode = .top
textField.rightView?.bounds.size.height += 10
textField.rightViewMode = .always
...
Rafael Sachetto
fuente
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.

Mukesh Shakya
fuente
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()
    }

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

}

//------------------------------------------------------------------------------
Swany
fuente