Inserção de texto para UITextField?

Respostas:

628

A substituição -textRectForBounds:alterará apenas a inserção do texto do espaço reservado. Para alterar a inserção do texto editável, você também precisa substituir-editingRectForBounds:

// placeholder position
- (CGRect)textRectForBounds:(CGRect)bounds {
     return CGRectInset(bounds, 10, 10);
}

// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
     return CGRectInset(bounds, 10, 10);
}
azdev
fonte
10
Essa solução funcionou para mim, embora eu tenha usado um valor de retorno de CGRectInset (limites, 9, 0); Eu também precisava definir esse valor para textRectForBounds, editRectForBounds e placeholderRectForBounds.
RyJ
2
Esta solução não funciona bem com o clearButton. O texto dentro do botão TextField se sobrepõe.
Piotr
Eu acho que, a substituição dos métodos acima fará com que a rolagem seja lenta, se UITextFieldresidir em a UIScrollView.
Bharat Dodeja
2
Para colocar o ClearButton: - (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); } Encontrado aqui: stackoverflow.com/questions/5361369/...
Miros
22
Sugiro chamar [super textRectForBounds: bounds] e [super editorRectForBounds: bounds] antes de chamar CGRectInset (bounds, 10, 10). Isso corrigirá o problema de sobreposição do botão Limpar.
Mrvincenzo # 27/13
294

Consegui fazer isso através de:

myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);

É claro que lembre-se de importar o QuartzCore e também adicionar o Framework ao seu projeto.

chuthan20
fonte
38
+1 para a criatividade, mas isso é um pouco problemático pouco, move-se também de exclusão botão dentro textfield
Nikita
2
você poderia fazer myTextField.layer.sublayers, que é uma matriz de todas as subcamadas ... e se sua UIImageView <- Estou assumindo que o X é uma imagem .. ou talvez UIButton ... ou você pode fazer um loop completo de cada uma e ver qual pertence a qual subexibição ... mas myfield.layer.sublayerTransform todas as subcamadas e, assim, o botão X movendo bem ..
chuthan20
Esta solução não está funcionando para mim. Só posso definir as margens esquerda e superior, mas não direita e inferior. UITextFieldsobrepõe o conteúdo no lado direito.
Bharat Dodeja
2
Esta é a melhor solução sem subclasse e não requer que visualizações extras e desnecessárias sejam colocadas na tela! +1!
Rambatino 10/11/14
1
@ jeet.chanchawat O botão X no lado direito nesta imagem .. developer.apple.com/library/content/documentation/…
chuthan20 13/16
169

Se você precisar de apenas uma margem esquerda, pode tentar o seguinte:

UItextField *textField = [[UITextField alloc] initWithFrame:...];
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, textField.frame.size.height)];
leftView.backgroundColor = textField.backgroundColor;
textField.leftView = leftView;
textField.leftViewMode = UITextFieldViewModeAlways;

Funciona para mim. Espero que isso possa ajudar.

roberto.buratti
fonte
17
Isso é muito mais fácil do que subclassificar apenas para obter uma inserção e permite adicionar qualquer visualização arbitrária à esquerda (você também pode usar o rightView para colocar algo à direita). Melhor do que a resposta aceita IMHO.
Kenny Grant
4
+1 fácil, sem subclassificação e projetado para funcionar com propriedades do campo de texto (em vez de "hacking").
So Over It
Terceira linha deve ser leftView.backgroundColor = textField.backgroundColor;... Fora isso ótima solução ... Obrigado (:
Aviel Gross
Não é tão elegante / completo quanto a resposta do azdev, mas uma ótima solução para um caso comum e simples!
Rembrandt P. Einstein
1
A subclasse poupará muito tempo com essa resposta, a menos que você tenha uma única caixa de texto para a qual precisa.
Crake
168

Em uma classe derivada de UITextField, substitua pelo menos esses dois métodos:

- (CGRect)textRectForBounds:(CGRect)bounds;
- (CGRect)editingRectForBounds:(CGRect)bounds;

Pode ser tão simples assim se você não tiver conteúdo adicional:

return CGRectInset(bounds , 10, 10);

O UITextField fornece vários métodos de posicionamento que você pode substituir.

desenhado
fonte
2
Sim, se você não substituir o arquivo EditRectForBounds, receberá o texto ao editar na parte superior esquerda do campo de texto. - (CGRect) editRectForBounds: limites (CGRect) {retornam CGRectInset (limites, 10, 10); }
Mark W
1
Acabou de editar a resposta para integrar método editingRectForBounds em
ıɾuǝʞ
5
Isso me parece um truque horrível - você também precisa substituir #- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
Zorayr
98

Como cerca de um @IBInspectable, @IBDesignableclasse rápida.

@IBDesignable
class TextField: UITextField {
    @IBInspectable var insetX: CGFloat = 6 {
       didSet {
         layoutIfNeeded()
       }
    }
    @IBInspectable var insetY: CGFloat = 6 {
       didSet {
         layoutIfNeeded()
       }
    }

    // placeholder position
    override func textRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , insetX , insetY)
    }

    // text position
    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , insetX , insetY)
    }
}

Você verá isso no seu storyboard.

insira a descrição da imagem aqui

Atualização - Swift 3

@IBDesignable
class TextField: UITextField {
    @IBInspectable var insetX: CGFloat = 0
    @IBInspectable var insetY: CGFloat = 0

    // placeholder position
    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: insetX, dy: insetY)
    }

    // text position
    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: insetX, dy: insetY)
    }
}
amassar
fonte
1
Achei o efeito em Y indesejado, não quero encolher o retângulo para o texto, e sim empurrá-lo para a linha de base do campo. Eu ajustei as implementações paralet rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
Chris Wagner
1
E adicione também se yo estão usando espaço reservado `substituição func placeholderRectForBounds (limites: CGRect) -> CGRect {return CGRectInset (limites, insetX, insetY)}`
RameshVel
Estranhamente, isso (definir as inserções em textRect/ editingRect) afeta o desempenho da rolagem (pelo menos no iOS 12), quando o texto excede o retângulo visível. Com uma inserção de 15, até pára de rolar.
Ixx
29

Se você tiver um botão claro, a resposta aceita não funcionará para você. Também devemos nos prevenir contra a Apple de mudar as coisas no futuro, chamandosuper .

Portanto, para garantir que o texto não se sobreponha ao botão Limpar, vamos obter o valor 'padrão' em super e ajustar conforme necessário.

Este código adicionará inserções de 10px na parte superior, esquerda e inferior do campo de texto:

@interface InsetTextField : UITextField

@end


@implementation InsetTextField

// Placeholder position
- (CGRect)textRectForBounds:(CGRect)bounds {
    CGRect rect = [super textRectForBounds:bounds];
    UIEdgeInsets insets = UIEdgeInsetsMake(10, 10, 10, 0);

    return UIEdgeInsetsInsetRect(rect, insets);
}

// Text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
    CGRect rect = [super editingRectForBounds:bounds];
    UIEdgeInsets insets = UIEdgeInsetsMake(10, 10, 10, 0);

    return UIEdgeInsetsInsetRect(rect, insets);
}

// Clear button position
- (CGRect)clearButtonRectForBounds:(CGRect)bounds {
    CGRect rect = [super clearButtonRectForBounds:bounds];

    return CGRectOffset(rect, -5, 0);
}

@end

Nota: UIEdgeInsetsMake aceita parâmetros na ordem: superior , esquerda , inferior , direita .

Chris Nolet
fonte
Usar textRectForBounds:e editingRectForBounds:métodos sem clearButtonRectForBounds: no iOS 7 ou superior funcionou para mim.
Stunner
clearButtonRectForBounds:apenas ajuda a empurrar um pouco o botão Limpar para a esquerda. Você pode deixar de fora. Meu campo de texto estava em um fundo escuro e o botão Limpar precisava de um pouco de preenchimento extra à direita.
precisa
Estranhamente, isso afeta o desempenho da rolagem (pelo menos no iOS 12), quando o texto excede o retângulo visível. Com uma inserção de 15, até pára de rolar.
Ixx
22

Pensei em fornecer uma solução rápida

import UIKit

class TextField: UITextField {
    let inset: CGFloat = 10

    // placeholder position
    override func textRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , inset , inset)
    }

    // text position
    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds , inset , inset)
    }

    override func placeholderRectForBounds(bounds: CGRect) -> CGRect {
        return CGRectInset(bounds, inset, inset) 
    }
}

Swift 3+

import UIKit

class TextField: UITextField {
    let inset: CGFloat = 10

    // placeholder position
    override func textRect(forBounds: CGRect) -> CGRect {
        return forBounds.insetBy(dx: self.inset , dy: self.inset)
    }

    // text position
    override func editingRect(forBounds: CGRect) -> CGRect {
        return forBounds.insetBy(dx: self.inset , dy: self.inset)
    }

    override func placeholderRect(forBounds: CGRect) -> CGRect {
        return forBounds.insetBy(dx: self.inset, dy: self.inset)
    }
}
smitt04
fonte
2
Não esqueça # override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
Eugene Braginets 31/03
No Swift 3, você deve usar o método 'CGRect.insetBy ()'
Den
1
No iOS 11, pelo menos, se você substituir textRectForBounds, o espaço reservado também será afetado - portanto, adicionar a substituição do espaço reservado fará com que o espaço reservado seja mais 10pt. Se é isso que você está procurando, 👍🏼, mas se não, é bom estar ciente.
DesignatedNerd
Estranhamente, isso afeta o desempenho da rolagem (pelo menos no iOS 12), quando o texto excede o retângulo visível. Com uma inserção de 15, até pára de rolar.
Ixx
14

Usar textRectForBounds:é a abordagem correta. Eu envolvi isso na minha subclasse para que você possa simplesmente usar textEdgeInsets. Veja SSTextField .

Sam Soffes
fonte
Essa abordagem, juntamente com o uso de cocoapods para importar o pod do SSToolkit, funciona muito bem - acho que esse é o caminho mais interessante a seguir.
Chris
Obrigado Chris! Que bom que você achou útil.
Sam Soffes 20/03
14

Rápido

 class TextField: UITextField {

    let inset: CGFloat = 8

    // placeholder position
    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: inset, dy: inset)
    }

    // text position
    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: inset, dy: inset)
    }
}
lcl
fonte
Estranhamente, isso afeta o desempenho da rolagem (pelo menos no iOS 12), quando o texto excede o retângulo visível. Com uma inserção de 15, até pára de rolar.
Ixx
12

Para as pessoas que estão procurando uma solução mais fácil.

Adicione o UITextFieldinterior a UIView. Para simular uma inserção ao redor do campo de texto, mantenho 10 px restantes e a largura é 20px menor que a visualização. Para uma borda de canto arredondado ao redor do campo de texto, use a borda da exibição

viewBG.layer.cornerRadius = 8.0;
viewBG.layer.borderColor = [UIColor darkGrayColor].CGColor;
viewBG.layer.borderWidth = 1.0;
karim
fonte
2
Honestamente, apenas colocar um UIView atrás do UITextField é a melhor e mais simples solução. Torne o UITextField transparente e pronto. Alinhei-o com um UITextView - acaba por ser cerca de 6 pixels inseridos. Muito mais fácil e também mais flexível do que criar uma subclasse ...
n13
Um problema com essa abordagem é o local onde a barra de rolagem aparecerá.
Doug Amos
@DougAmos What scrollbar? Você está se referindo a UITextViewtalvez?
significado-importa
12

Você pode definir a inserção de texto para UITextField, definindo o leftView.

Como isso:

UITextField *yourTextField = [[UITextField alloc] init];
UIView *leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
leftView.backgroundColor = [UIColor clearColor];
yourTextField.leftViewMode = UITextFieldViewModeAlways;
yourTextField.leftView = leftView;
Dourado
fonte
1
Quando você também precisa usar a vista esquerda para um ícone, isso não funciona
Reaper
@Reaper esse método também funcionará para uma imagem. adicione a quantidade de preenchimento desejada à largura do quadro de visualização de imagem e defina o modo de conteúdo como central. imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
Andy
isso é muito hacky. já existe um método textRectForBounds para definir a inserção
Gerald
12

Rápido

    // adjust place holder text
    let paddingView = UIView(frame: CGRectMake(0, 0, 10, usernameOrEmailField.frame.height))
    usernameOrEmailField.leftView = paddingView
    usernameOrEmailField.leftViewMode = UITextFieldViewMode.Always
LondonGuy
fonte
1
Esta é uma solução realmente barata e fácil. Obrigado!
shnaz
11

Uma boa abordagem para adicionar preenchimento ao UITextField é subclassificar o UITextField e adicionar uma propriedade edgeInsets. Você define o edgeInsets e o UITextField será desenhado de acordo. Isso também funcionará corretamente com um conjunto leftView ou rightView personalizado.

OSTextField.h

#import <UIKit/UIKit.h>

@interface OSTextField : UITextField

@property (nonatomic, assign) UIEdgeInsets edgeInsets;

@end

OSTextField.m

#import "OSTextField.h"

@implementation OSTextField

- (id)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {
        self.edgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
    }
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder{
    self = [super initWithCoder:aDecoder];
    if(self){
        self.edgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
    }
    return self;
}

- (CGRect)textRectForBounds:(CGRect)bounds {
    return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}

- (CGRect)editingRectForBounds:(CGRect)bounds {
    return [super editingRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}

@end
Brody Robertson
fonte
Boa resposta. Fontes da propriedade faltando :-)
phatmann
6

Swift 3 / Designável no construtor de interfaces / Insetos horizontais e verticais separados / utilizável fora da caixa

@IBDesignable
class TextFieldWithPadding: UITextField {

@IBInspectable var horizontalInset: CGFloat = 0
@IBInspectable var verticalInset: CGFloat = 0

override func textRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: horizontalInset, dy: verticalInset)
}

override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: horizontalInset , dy: verticalInset)
}

override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: horizontalInset, dy: verticalInset)
}
}

uso:

uso

&

insira a descrição da imagem aqui

zgorawski
fonte
5

Fiz isso no IB, onde criei um UIView Behind the textView que foi um pouco mais longo. Com a cor de fundo do campo de texto definida como clara. insira a descrição da imagem aqui

jeremy wilson
fonte
5

É a maneira mais rápida que encontrei sem fazer nenhuma subclasse:

UIView *spacerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10., 10.)];
[textField setLeftViewMode:UITextFieldViewModeAlways];
[textField setLeftView:spacerView];

Em Swift:

let spacerView = UIView(frame:CGRect(x:0, y:0, width:10, height:10))
textField.leftViewMode = UITextFieldViewMode.Always
textField.leftView = spacerView
Máx.
fonte
4

Aqui está o mesmo UITextField subclasse escrito em Swift 3. É bem diferente das versões anteriores do Swift, como você verá:

import UIKit

class MyTextField: UITextField
    {
    let inset: CGFloat = 10

    // placeholder position
    override func textRect(forBounds bounds: CGRect) -> CGRect
        {
        return bounds.insetBy(dx: inset, dy: inset)
        }

    // text position
    override func editingRect(forBounds bounds: CGRect) -> CGRect
        {
        return bounds.insetBy(dx: inset, dy: inset)
        }

    override func placeholderRect(forBounds bounds: CGRect) -> CGRect
        {
        return bounds.insetBy(dx: inset, dy: inset)
        }
    }

Aliás, você também pode fazer algo como o seguinte, se quiser controlar a inserção de apenas um lado. Este exemplo específico de ajustar apenas a inserção esquerda é útil se você colocar uma imagem em cima do UITextField, mas desejar que ela pareça ao usuário estar dentro do campo de texto:

    override func editingRect(forBounds bounds: CGRect) -> CGRect
        {
        return CGRect.init(x: bounds.origin.x + inset, y: bounds.origin.y, width: bounds.width - inset, height: bounds.height)
        }
Gene Loparco
fonte
4

Versão Swift 4.2 :

import UIKit

class InsetTextField: UITextField {

  let inset: CGFloat = 10

  override func textRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: inset, dy: inset)
  }


  override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: inset, dy: inset)
  }

  override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
    return bounds.insetBy(dx: inset, dy: inset)
  }

}
Bruno Paulino
fonte
Estranhamente, isso afeta o desempenho da rolagem (pelo menos no iOS 12), quando o texto excede o retângulo visível. Com uma inserção de 15, até pára de rolar.
Ixx
3

Você pode ajustar o posicionamento do texto em um campo de texto, tornando-o uma subclasse UITextFielde substituindo o -textRectForBounds:método.

Noah Witherspoon
fonte
3

É um absurdo você ter que subclassificar, pois UITextFieldjá implementa os métodos, como aponta @Adam Waite. Aqui está uma extensão rápida que expõe um método de fábrica, também disponível em nosso repositório de categorias :

private class InsetTextField: UITextField {
    var insets: UIEdgeInsets

    init(insets: UIEdgeInsets) {
        self.insets = insets
        super.init(frame: CGRectZero)
    }

    required init(coder aDecoder: NSCoder) {
        fatalError("not intended for use from a NIB")
    }

    // placeholder position
    override func textRectForBounds(bounds: CGRect) -> CGRect {
        return super.textRectForBounds(UIEdgeInsetsInsetRect(bounds, insets))
    }

    // text position
    override func editingRectForBounds(bounds: CGRect) -> CGRect {
        return super.editingRectForBounds(UIEdgeInsetsInsetRect(bounds, insets))
    }
}

extension UITextField {

    class func textFieldWithInsets(insets: UIEdgeInsets) -> UITextField {
        return InsetTextField(insets: insets)
    }

}
Christopher Pickslay
fonte
O link da sua resposta está esgotado. Você pode atualizá-lo?
WendiKidd 17/09/2015
Corrigido o URL @WendiKidd
Christopher Pickslay
2

Subcloquei o UITextField para lidar com isso que suporta inserção esquerda, superior, direita e inferior e também o posicionamento claro dos botões.

MRDInsetTextField.h

#import <UIKit/UIKit.h>

@interface MRDInsetTextField : UITextField

@property (nonatomic, assign) CGRect inset;

@end

MRDInsetTextField.m

#import "MRDInsetTextField.h"

@implementation MRDInsetTextField

- (id)init
{
    self = [super init];
    if (self) {
        _inset = CGRectZero;
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        _inset = CGRectZero;
    }
    return self;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        _inset = CGRectZero;
    }
    return self;
}

- (void)setInset:(CGRect)inset {
    _inset = inset;

    [self setNeedsLayout];
}

- (CGRect)getRectForBounds:(CGRect)bounds withInset:(CGRect)inset {

    CGRect newRect = CGRectMake(
                         bounds.origin.x + inset.origin.x,
                         bounds.origin.y + inset.origin.y,
                         bounds.origin.x + bounds.size.width - inset.origin.x - inset.size.width,
                         bounds.origin.y + bounds.size.height - inset.origin.y - inset.size.height
                         );

    return newRect;
}

- (CGRect)textRectForBounds:(CGRect)bounds {
    return [self getRectForBounds:[super textRectForBounds:bounds] withInset:_inset];
}

- (CGRect)placeholderRectForBounds:(CGRect)bounds {
    return [self getRectForBounds:bounds withInset:_inset];
}

- (CGRect)editingRectForBounds:(CGRect)bounds {
    return [self getRectForBounds:[super editingRectForBounds:bounds] withInset:_inset];
}

- (CGRect)clearButtonRectForBounds:(CGRect)bounds {
    return CGRectOffset([super clearButtonRectForBounds:bounds], -_inset.size.width, _inset.origin.y/2 - _inset.size.height/2);
}

@end

Exemplo de uso em que * _someTextField * vem da visualização de ponta / storyboard com a classe personalizada MRDInsetTextField

[(MRDInsetTextField*)_someTextField setInset:CGRectMake(5, 0, 5, 0)]; // left, top, right, bottom inset
Firula
fonte
Obrigado. Porém, uma sugestão para o seu código - por que você usou o CGRect para inserir e não o UIEdgeInsets?
sha
2

Isso não é tão curto quanto os outros exemplos, mas adota uma abordagem totalmente diferente para resolver esse problema. Observe que o cursor ainda começará a nivelar para a borda esquerda, mas o texto será recuado adequadamente quando digitado / exibido. Isso funciona sem subclassificar se você está procurando apenas uma margem esquerda e você já está usandoUITextFieldDelegate seus campos de texto. Você precisa definir os atributos de texto padrão e os atributos de digitação. Você define os atributos de texto padrão ao criar o campo de texto. Os atributos de digitação que você precisa definir no delegado. Se você também estiver usando um espaço reservado, também será necessário definir a mesma margem. Juntando tudo, você obtém algo parecido com isto.

Primeiro, crie uma categoria na UITextFieldclasse.

//  UITextField+TextAttributes.h

#import <UIKit/UIKit.h>

@interface UITextField (TextAttributes)

- (void)setIndent:(CGFloat)indent;

@end


//  UITextField+TextAttributes.m
#import "UITextField+TextAttributes.h"

@implementation UITextField (TextAttributes)

- (void)setTextAttributes:(NSDictionary*)textAttributes indent:(CGFloat)indent
{
    if (!textAttributes) return;

    NSMutableParagraphStyle *paragraphStyle = [textAttributes objectForKey:NSParagraphStyleAttributeName];
    paragraphStyle.firstLineHeadIndent = indent;
    paragraphStyle.headIndent = indent;
}

- (void)setIndent:(CGFloat)indent
{
   [self setTextAttributes:self.defaultTextAttributes indent:indent];
   [self setTextAttributes:self.typingAttributes indent:indent];
}

@end

Em seguida, se você estiver usando suportes posicionados, certifique-se de usar um espaço reservado atribuído configurando o mesmo recuo. Crie um dicionário atribuído padrão com os atributos adequados, algo como isto:

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.firstLineHeadIndent = 7;
paragraphStyle.headIndent = 7;
NSDictionary *placeholderAttributes = [NSDictionary dictionaryWithObjectsAndKeys: paragraphStyle, NSParagraphStyleAttributeName, nil];

Em seguida, importe a categoria acima e sempre que criar um campo de texto, defina o recuo padrão, o delegado e use os atributos de espaço reservado padrão definidos acima. Por exemplo:

UITextField *textField = [[UITextField alloc] init];
textField.indent = 7;
textField.delegate = self;
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"Placeholder Text" attributes:placeholderAttributes];

Por fim, no delegado, implemente o textFieldDidBeginEditingmétodo, algo como isto:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    textField.indent = 7;
}
user3878720
fonte
A suposição que defaultTextAttributescontém NSMutableParagraphStyleé bastante perigosa. Prefiro que seja mutável. Copie tudo isso.
Ben Sinclair
1

Eu normalmente tento evitar subclasses, mas isso funciona se você já tiver:

// add a property 
@property (nonatomic) UIEdgeInsets edgeInsets;

// and override:

- (CGRect)textRectForBounds:(CGRect)bounds
{
    return [super textRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}

- (CGRect)editingRectForBounds:(CGRect)bounds
{
    return [super editingRectForBounds:UIEdgeInsetsInsetRect(bounds, self.edgeInsets)];
}
Adam Waite
fonte
Alguma razão para você evitar subclasses? Ele é um paradigma de design válido.
Stunner
1

Para lançar outra solução que não precisa de subclassificação:

UITextField *txtField = [UITextField new];
txtField.borderStyle = UITextBorderStyleRoundedRect;

// grab BG layer
CALayer *bgLayer = txtField.layer.sublayers.lastObject;
bgLayer.opacity = 0.f;

// add new bg view
UIView *bgView = [UIView new];
bgView.backgroundColor = [UIColor whiteColor];
bgView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
bgView.userInteractionEnabled = NO;

[txtField addSubview: bgView];
[txtField sendSubviewToBack: bgView];

Original UITextField Fixed UITextField

Testado com iOS 7 e iOS 8. Ambos funcionando. Ainda assim, pode haver a chance de a Apple modificar a hierarquia de camadas do UITextField, estragando muito as coisas.

TheGrumpyCoda
fonte
1

Aqui está uma resposta abrangente do Swift que inclui um leftView (ícone personalizado) e um botão de limpeza personalizado, ambos configurados no Interface Builder com inserções personalizáveis.

import UIKit

@IBDesignable
class InsetTextField: UITextField {
@IBInspectable var leftInset:CGFloat = 0
@IBInspectable var rightInset:CGFloat = 0
@IBInspectable var icon:UIImage? { didSet {
    let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 16, height: 16))
    imageView.image = icon
    self.leftView = imageView
    self.leftViewMode = .Always
} }

@IBInspectable var clearButton:UIImage? { didSet {
    let button = UIButton(type: .Custom)
    button.setImage(clearButton, forState: .Normal)
    button.addTarget(self, action: "clear", forControlEvents: UIControlEvents.TouchUpInside)
    button.frame = CGRect(x: 0, y: 0, width: 18, height: 18)
    self.rightView = button
    self.rightViewMode = .WhileEditing
} }

func clear() {
    self.text = ""
}

override func leftViewRectForBounds(bounds: CGRect) -> CGRect {
    var height:CGFloat = 0
    var width:CGFloat = 0
    if let leftView = self.leftView {
        height = leftView.bounds.height
        width = leftView.bounds.width
    }

    return CGRect(x: leftInset, y: bounds.height/2 - height/2, width: width, height: height)
}

override func rightViewRectForBounds(bounds: CGRect) -> CGRect {
    var height:CGFloat = 0
    var width:CGFloat = 0
    if let rightView = self.rightView {
        height = rightView.bounds.height
        width = rightView.bounds.width
    }

    return CGRect(x: bounds.width - width - rightInset, y: bounds.height/2 - height/2, width: width, height: height)
}

}
rmooney
fonte
1

Uma solução que realmente funciona e abrange todos os casos:

  • Deve usar offsetBynão insetBy.
  • Também deve chamar a super função para obter o original Rect.
  • Limites está com defeito. você precisa deslocar o X, Y original. Os limites têm X, Y como zeros.
  • O x, y original pode ser diferente de zero, por exemplo, ao definir o leftView do UITextField.

Amostra:

override func textRect(forBounds bounds: CGRect) -> CGRect {
    return super.textRect(forBounds: bounds).offsetBy(dx: 0.0, dy: 4)
}


override func editingRect(forBounds bounds: CGRect) -> CGRect {
    return super.editingRect(forBounds: bounds).offsetBy(dx: 0.0, dy: 4)
}
hasan
fonte
0

Se você deseja alterar apenas o recuo SUPERIOR e ESQUERDO,

// posição do marcador

- (CGRect)textRectForBounds:(CGRect)bounds {

CGRect frame = bounds;
frame.origin.y = 3;
 frame.origin.x = 5;
bounds = frame;
return CGRectInset( bounds , 0 , 0 );
}

// posição do texto

- (CGRect)editingRectForBounds:(CGRect)bounds {

CGRect frame = bounds;
frame.origin.y = 3;
 frame.origin.x = 5;
bounds = frame;
return CGRectInset( bounds , 0 , 0 );
}
Mann
fonte
-1

Solução rápida sem subclasse e também inspecionável

extension UITextField {
    @IBInspectable var textInsets: CGPoint {
            get {
                return CGPoint.zero
            }
            set {
                layer.sublayerTransform = CATransform3DMakeTranslation(newValue.x, newValue.y, 0);
            }
        }
}
Bhavesh Tiwari
fonte