Preenchimento UITextfield leftView / rightView no iOS7


93

As visualizações leftView e rightView de um UITextField no iOS7 estão realmente perto da borda do campo de texto.

Como posso adicionar algum preenchimento (horizontal) a esses itens?

Tentei modificar a moldura, mas não funcionou

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

Observe que não estou interessado em adicionar preenchimento ao texto do campo de texto, como este Definir preenchimento para UITextField com UITextBorderStyleNone


possível duplicata da inserção
Zorayr

1
Não, isso está perguntando sobre o recuo da imagem exibida como leftView em um campo de texto. Sem recuar o próprio texto. Experimente o código dele e você verá que definir leftView para uma imagem coloca essa imagem contra a borda esquerda do campo de texto, sem preenchimento. Parece feio.
pedra de

Respostas:


90

Estava trabalhando nisso sozinho e usei esta solução:

- (CGRect) rightViewRectForBounds:(CGRect)bounds {

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

Isso moverá a imagem da direita em 10 em vez de ter a imagem comprimida contra a borda no iOS 7.

Além disso, isso estava em uma subclasse de UITextField, que pode ser criada por:

  1. Crie um novo arquivo que seja uma subclasse em UITextFieldvez do padrãoNSObject
  2. Adicione um novo método chamado - (id)initWithCoder:(NSCoder*)coderpara definir a imagem

    - (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. Você pode ter que importar #import <QuartzCore/QuartzCore.h>

  4. Adicione o rightViewRectForBoundsmétodo acima

  5. No Interface Builder, clique no TextField que deseja criar como subclasse e altere o atributo de classe para o nome desta nova subclasse


como usar o IBDesignable para isso mesmo?
riddhi

167

Uma solução muito mais simples, que tira proveito de 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;

Em 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
Você pode usar ScaleAspectFit também em vez de centralizar ... se o tamanho da imagem não corresponder ao quadro exato.
Mihir Mehta

Usei seu exemplo para UIButton (em vez de UIImageView) enquanto seu tipo é InfoLight.
OhadM de

Descobri que ".right" em vez de ".center" faz com que pareça mais com uma barra de Pesquisa integrada, como a do aplicativo Contatos. Ótima solução para isso, obrigado por postá-la.
James Toomey

Ou se você precisar ser preciso na recriação do design, coloque a imagem à esquerda e aumente a largura para obter o preenchimento exato
jovanjovanovic

4
Isso parece não funcionar mais com iOS 13 e Xcode 11 Beta 7. Funciona bem no iOS 11/12.
PatrickDotStar

49

A maneira mais fácil é adicionar um UIView ao leftView / righView e adicionar um ImageView ao UIView, ajustar a origem do ImageView dentro do UIView em qualquer lugar que você quiser, isso funcionou para mim como um encanto. Precisa de apenas algumas linhas 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 não funciona, mas essa resposta funciona perfeitamente!
nigong

14

Isso funciona muito bem para o 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

não é possível converter o valor do tipo 'string' para o tipo de argumento esperado 'UIImage? "

7

Isso funciona para mim

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

Que te ajude.


6

Gosto desta solução porque resolve o problema com uma única linha de código

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

Nota: .. ou 2 se você considerar incluir uma linha QuartzCore :)


1
Isso também move a fronteira
Softlion

1
mas não resolve o problema do preenchimento direito, apenas o problema do preenchimento esquerdo
carmen_munich

1
Tive um resultado melhor usando rightView.layer.sublayerTransform = CATransform3DMakeTranslation (-10.0f, 0.0f, 0.0f), mas +1 para o método
Thibaud David

Lembre-se de que isso também mudará o botão "limpar" do campo de texto para a direita, o que pode empurrá-lo para além da borda do campo de texto. Se você não precisa do botão limpar, esta é uma ótima abordagem, caso contrário, talvez não.
Tom Harrington de

4

A melhor maneira de fazer isso é simplesmente criar uma classe usando a subclasse de UITextField e no arquivo .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;

}

fazendo isso, vá para seu storyboard ou xib e clique no inspetor de identidade e substitua UITextfield por seu próprio "CustomTextField" na opção de classe.

Nota: Se você simplesmente fornecer preenchimento com layout automático para o campo de texto, seu aplicativo não será executado e mostrará apenas a tela em branco.


3

Eu encontrei isso em algum lugar ...

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

[self addSubview:itemDescription];

4
Isso apenas adiciona preenchimento ao texto, que não é o que o autor da pergunta está procurando. Ele não quer um leftView claro. Ele quer uma imagem exibida como leftView.
pedra de

Você pode simplesmente adicionar a imagem no paddingView.
Matheus Weber

3

Em vez de manipular imageView ou image, podemos substituir um método fornecido pela 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
}}

e da mesma forma, podemos substituir a função abaixo para visualização à esquerda.

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

}

3

Swift 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
    }
}

Você vai querer:

  • Subclasse UITextField
  • Escreva um método invalidate dentro do campo de texto da subclasse
  • No método invalidate, crie um UIView maior do que sua imagem
  • Coloque sua imagem dentro da vista
  • Atribuir a vista para UITextField.rightView

2

Aqui está uma solução:

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

1

Crie uma classe UITextField personalizada e use essa classe em vez de UITextField. Substituir - (CGRect) textRectForBounds: (CGRect) limites para definir o retângulo que você precisa

Exemplo

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

1

O exemplo abaixo é para adicionar preenchimento horizontal a uma visão esquerda que passa a ser um ícone - você pode usar uma abordagem semelhante para adicionar preenchimento a qualquer uma UIViewque gostaria de usar como visão esquerda do campo de texto.

UITextFieldSubclasse interna :

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));
}

Embora sejamos uma subclasse UITextFieldaqui, acredito que essa seja a abordagem mais limpa.


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

Se o UITextFieldestiver incorporado em a UISearchBar, como você instrui o UISearchBara usar sua UITextFieldsubclasse?
crishoj de

1

Obrigado a vocês por suas respostas, para minha surpresa nenhum deles realmente ajustou a imagem de visão certa ao meu campo de texto, embora ainda fornecesse o preenchimento necessário. então pensei em usar o modo AspectFill e milagres aconteceram. para futuros candidatos, aqui está o que usei:

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;

o 35 no quadro do meu imageview representa a altura do meu e-mailTextfield, fique à vontade para ajustá-lo às suas necessidades.


1

Eu mesmo tive esse problema e, de longe, a solução mais fácil é modificar sua imagem para simplesmente adicionar preenchimento a cada lado da imagem!

Acabei de alterar minha imagem png para adicionar 10 pixels de preenchimento transparente, e funciona bem, sem codificação alguma!


1

Se você estiver usando um UIImageView como leftView, deverá usar este código:

Cuidado: Não use dentro de viewWillAppear ou 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

Eu criei um método personalizado na minha classe ViewController, como mostrado abaixo:

- (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;
}

Agora posso chamar esse método dentro de ( viewDidLoadmétodo) e enviar qualquer um dos meus TextFieldspara esse método e adicionar preenchimento para a direita e para a esquerda e fornecer cores de texto e de fundo escrevendo apenas uma linha de código, da seguinte maneira:

[self modifyTextField:self.firstNameTxtFld];

Funcionou perfeitamente no iOS 7! Espero que isso ainda funcione no iOS 8 e 9 também!

Eu sei que adicionar muitas visualizações pode tornar este objeto um pouco mais pesado para ser carregado. Mas, quando preocupado com a dificuldade em outras soluções, me vi mais inclinado a este método e mais flexível em usar desta forma. ;)

Espero que esta resposta possa ser útil ou útil para descobrir outra solução para outra pessoa.

Felicidades!


1

Isso funciona para mim exatamente como estou procurando:

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 e Xcode 11, esta é a única solução que funciona para nós.

// 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
    }
}

As respostas acima não funcionam para mim, esta funciona.
Mark Dylan B Mercado

1

// Definir Rightview 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

Um truque: adicione um UIView contendo UIImageView a UITextField como rightView. Este UIView deve ser maior em tamanho, agora coloque o UIImageView à esquerda dele. Portanto, haverá um preenchimento de espaço da direita.

// 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

A maneira mais fácil é alterar o campo de texto como RoundRect em vez de Custom e ver a mágica. :)


0

para Swift2, eu 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

Abordagem simples:

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

Observação: a altura deve ser menor que a largura para permitir o preenchimento horizontal.


0

Percebi que este é um post antigo e esta resposta é um pouco específica para o meu caso de uso, mas eu postei no caso de outros estarem procurando uma solução semelhante. Eu quero mover leftView ou rightView de um UITextField, mas não estou colocando imagens neles e não quero nenhuma constante codificada.

Minha interface do usuário pede para ocultar o botão limpar do campo de texto e exibir um UIActivityIndicatorView onde o botão limpar estava localizado.

Eu adiciono um botão giratório ao rightView, mas fora da caixa (no iOS 13) ele é deslocado 20 pixels para a direita do clearButton. Não gosto de usar números mágicos, pois a posição de clearButton e rightView estão sujeitos a alterações a qualquer momento pela Apple. A intenção do design da IU é "giratório onde o botão limpar está", então minha solução foi criar uma subclasse de UITextField e substituir rightViewRect(forBounds).

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

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

Abaixo está um exemplo de trabalho (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()
    }

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

}

//------------------------------------------------------------------------------
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.