Texto insertado para UITextField?

Respuestas:

628

La anulación -textRectForBounds:solo cambiará la inserción del texto del marcador de posición. Para cambiar el recuadro del texto editable, también debe anular-editingRectForBounds:

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

// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
     return CGRectInset(bounds, 10, 10);
}
azdev
fuente
10
Esta solución funcionó para mí, aunque utilicé un valor de retorno de CGRectInset (límites, 9, 0); También necesitaba establecer este valor para textRectForBounds, editRectForBounds y placeholderRectForBounds.
RyJ
2
Esta solución no funciona bien con clearButton. Texto dentro del botón de superposición de TextField.
Piotr
Creo que anular los métodos anteriores hará que el desplazamiento sea lento, si UITextFieldreside dentro de a UIScrollView.
Bharat Dodeja
2
Para colocar el ClearButton: - (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); } Encontrado aquí: stackoverflow.com/questions/5361369/…
Miros
22
Sugiero llamar a [super textRectForBounds: límites] y [super editingRectForBounds: límites] antes de llamar a CGRectInset (límites, 10, 10). Esto solucionará el problema de superposición de botones claros.
mrvincenzo
294

Pude hacerlo a través de:

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

Por supuesto, recuerde importar QuartzCore y también agregar el Framework a su proyecto.

chuthan20
fuente
38
+1 para la creatividad, pero esto es un poco problemático, también mueve el botón Eliminar dentro del campo de texto
Nikita
2
podría hacer myTextField.layer.sublayers, que es una matriz de todas las subcapas ... y si su UIImageView <- Supongo que la X es una imagen ... o tal vez UIButton ... o podría recorrer cada una de ellas y ver la cual uno pertenece a los que subvista ... pero myfield.layer.sublayerTransform todas las subcapas y por lo tanto el botón X en movimiento, así ..
chuthan20
Esta solución no me funciona. Solo puedo establecer el margen izquierdo y superior, pero no el derecho y el inferior. UITextFieldse superpone al contenido del lado derecho.
Bharat Dodeja
2
¡Esta es la mejor solución sin subclases y no requiere vistas adicionales innecesarias para colocar en la pantalla! +1!
Rambatino
1
@ jeet.chanchawat El botón X en el lado derecho de esta imagen ... developer.apple.com/library/content/documentation/…
chuthan20
169

Si solo necesita un margen izquierdo, puede probar esto:

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;

Esto funciona para mi. Espero que esto pueda ayudar.

roberto.buratti
fuente
17
Esto es mucho más fácil que subclasificar solo para obtener una inserción, y le permite agregar cualquier vista arbitraria a la izquierda (también puede usar rightView para colocar algo a la derecha). Mejor que la respuesta aceptada en mi humilde opinión.
Kenny Grant
44
+1 fácil, sin subclases, y diseñado para trabajar con propiedades de campo de texto (en lugar de 'pirateo').
So Over It
La tercera línea debería ser leftView.backgroundColor = textField.backgroundColor;... Aparte de esa gran solución ... Gracias (:
Aviel Gross
No es tan elegante / completo como la respuesta de azdev, ¡pero es una gran solución para un caso común y simple!
Rembrandt Q. Einstein
1
Subclasificar le ahorrará un montón de tiempo con esta respuesta, a menos que tenga un solo cuadro de texto para el que lo necesite.
Crake
168

En una clase derivada de UITextField, anule al menos estos dos métodos:

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

Puede ser tan simple como esto si no tiene contenido adicional:

return CGRectInset(bounds , 10, 10);

UITextField proporciona varios métodos de posicionamiento que puede anular.

dibujado hacia adelante
fuente
2
Sí, si no anula la edición de RectForBounds, obtendrá el texto cuando edite en la parte superior izquierda del campo de texto. - (CGRect) ediciónRectForBounds: (CGRect) límites {return CGRectInset (límites, 10, 10); }
Mark W
1
Acaba de editar la respuesta de integrar método editingRectForBounds en
ıɾuǝʞ
55
Esto me parece un truco horrible, también - (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
tendrías
98

¿Qué tal una @IBInspectable, @IBDesignableclase 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)
    }
}

Verás esto en tu guión gráfico.

ingrese la descripción de la imagen aquí

Actualización - 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)
    }
}
mezcla
fuente
1
Encontré el efecto en Y no deseado, no quiero reducir el rect para el texto, sino empujarlo hacia la línea base del campo. Ajusté las implementaciones alet rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
Chris Wagner
1
Y agregue esto también si está usando el marcador de posición `override func placeholderRectForBounds (límites: CGRect) -> CGRect {return CGRectInset (límites, insetX, insetY)}`
RameshVel
Curiosamente, esto (configurar las inserciones en textRect/ editingRect) afecta el rendimiento de desplazamiento (al menos en iOS 12), cuando el texto desborda el rectángulo visible. Con una inserción de 15, incluso deja de desplazarse.
Ixx
29

Si tiene un botón de borrar, la respuesta aceptada no funcionará para usted. También debemos evitar que Apple cambie las cosas en el futuro llamando super.

Entonces, para asegurarnos de que el texto no se superponga con el botón de borrar, obtengamos el valor 'predeterminado' desde el superprincipio, luego ajustemos según sea necesario.

Este código agregará una inserción de 10px en la parte superior, izquierda e inferior del 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 toma parámetros en el orden: arriba , izquierda , abajo , derecha .

Chris Nolet
fuente
El uso textRectForBounds:y los editingRectForBounds:métodos sin clearButtonRectForBounds: iOS 7+ funcionaron para mí.
Aturdidor
clearButtonRectForBounds:solo ayuda a empujar un poco el botón de borrar a la izquierda. Puede que quieras dejarlo fuera. Mi campo de texto estaba sobre un fondo oscuro, y el botón de borrar necesitaba un poco de relleno adicional a la derecha.
Chris Nolet
Extrañamente, esto afecta el rendimiento de desplazamiento (al menos en iOS 12), cuando el texto desborda el rectángulo visible. Con una inserción de 15, incluso deja de desplazarse.
Ixx
22

Pensé que proporcionaría una solución 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
fuente
2
No lo olvides override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
Eugene Braginets
En Swift 3 debe usar el método 'CGRect.insetBy ()'
Den
1
Al menos en iOS 11, si anula textRectForBounds, el marcador de posición también se ve afectado, por lo que agregar la anulación de marcador de posición inserta el marcador de posición otros 10 puntos más. Si eso es lo que estás buscando, 👍🏼, pero si no, es bueno tenerlo en cuenta.
DesignatedNerd
Extrañamente, esto afecta el rendimiento de desplazamiento (al menos en iOS 12), cuando el texto desborda el rectángulo visible. Con una inserción de 15, incluso deja de desplazarse.
Ixx
14

Usar textRectForBounds:es el enfoque correcto. He envuelto esto en mi subclase para que pueda usarlo textEdgeInsets. Ver SSTextField .

Sam Soffes
fuente
Este enfoque, junto con el uso de cocoapods para importar la cápsula SSToolkit, funciona muy bien, creo que esta es la mejor manera de hacerlo.
Chris
Gracias Chris! Me alegra que lo hayas encontrado útil.
Sam Soffes
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
fuente
Extrañamente, esto afecta el rendimiento de desplazamiento (al menos en iOS 12), cuando el texto desborda el rectángulo visible. Con una inserción de 15, incluso deja de desplazarse.
Ixx
12

Para las personas que buscan una solución más fácil.

Agregue el UITextFieldinterior a UIView. Para simular un recuadro alrededor del campo de texto, mantengo 10 px a la izquierda y el ancho es 20 px menos que la vista. Para un borde de esquina redondeada alrededor del campo de texto, use el borde de la vista

viewBG.layer.cornerRadius = 8.0;
viewBG.layer.borderColor = [UIColor darkGrayColor].CGColor;
viewBG.layer.borderWidth = 1.0;
karim
fuente
2
Honestamente, solo poner una UIView detrás del UITextField es la mejor y más simple solución. Haga que UITextField sea transparente y listo. Lo alineé con un UITextView; resulta que tiene unos 6 píxeles de inserción. Mucho más fácil y también más flexible que crear una subclase ...
n13
Un problema con este enfoque es la ubicación donde aparecerá la barra de desplazamiento.
Doug Amos
@DougAmos ¿Qué barra de desplazamiento? ¿Te refieres UITextViewquizás?
significado-asuntos
12

Puede configurar el recuadro de texto para UITextField configurando leftView.

Me gusta esto:

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;
dorado
fuente
1
Cuando también necesita usar la vista izquierda para un icono, esto no puede funcionar
Reaper
@Reaper este método también funcionará para una imagen. agregue la cantidad de relleno que desee al ancho del marco de la vista de imagen y establezca el modo de contenido en el centro. imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
Andy
Esto es demasiado hacky. ya existe un método textRectForBounds para configurar el recuadro
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
LondresGuy
fuente
1
Esta es una solución realmente barata y fácil. ¡Gracias!
shnaz
11

Un buen enfoque para agregar relleno a UITextField es subclasificar UITextField y agregar una propiedad edgeInsets. Luego configura los edgeInsets y el UITextField se dibujará en consecuencia. Esto también funcionará correctamente con un conjunto personalizado leftView o rightView.

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
fuente
Buena respuesta. Suministra la propiedad faltante :-)
phatmann
6

Swift 3 / Designable en el generador de interfaces / Separar insectos horizontales y verticales / utilizable de fábrica

@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

Y

ingrese la descripción de la imagen aquí

zgorawski
fuente
5

Hice esto en IB donde creé una UIView detrás del textView que fue un poco más larga. Con el color de fondo textField establecido en claro. ingrese la descripción de la imagen aquí

jeremy wilson
fuente
5

Es la forma más rápida que he encontrado sin hacer ninguna subclase:

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

En Swift:

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

Aquí está el mismo UITextField subclasificado escrito en Swift 3. Es bastante diferente de las versiones anteriores de Swift, como 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)
        }
    }

Por cierto, también puede hacer algo como lo siguiente, si desea controlar la inserción de un solo lado. Este ejemplo particular de ajustar solo el recuadro izquierdo es útil si coloca una imagen en la parte superior de UITextField pero desea que aparezca para el usuario dentro del 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
fuente
4

Versión 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
fuente
Extrañamente, esto afecta el rendimiento de desplazamiento (al menos en iOS 12), cuando el texto desborda el rectángulo visible. Con una inserción de 15, incluso deja de desplazarse.
Ixx
3

Puede ajustar el posicionamiento del texto dentro de un campo de texto convirtiéndolo en una subclase UITextFieldy anulando el -textRectForBounds:método.

Noah Witherspoon
fuente
3

Es absurdo que tengas que subclasificar, ya que UITextFieldya implementa los métodos, como señala @Adam Waite. Aquí hay una extensión rápida que expone un método de fábrica, también disponible en nuestro repositorio de categorías :

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
fuente
El enlace en su respuesta está muerto, ¿puede actualizarlo?
WendiKidd
Se corrigió la URL @WendiKidd
Christopher Pickslay
2

Subclasé UITextField para manejar esto que admite la inserción izquierda, superior, derecha e inferior, y también la posición clara del botón.

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

Ejemplo de uso donde * _someTextField * proviene de la vista nib / storyboard con la clase personalizada MRDInsetTextField

[(MRDInsetTextField*)_someTextField setInset:CGRectMake(5, 0, 5, 0)]; // left, top, right, bottom inset
Firula
fuente
Gracias. Sin embargo, una sugerencia para su código: ¿por qué utilizó CGRect para insertar y no UIEdgeInsets?
sha
2

Esto no es tan corto como los otros ejemplos, pero adopta un enfoque completamente diferente para resolver este problema. Tenga en cuenta que el cursor aún comenzará a ras hasta el borde izquierdo, pero el texto se sangrará correctamente cuando se escriba / muestre. Esto funciona sin subclasificar si está buscando solo un margen izquierdo y ya está utilizando UITextFieldDelegatesus campos de texto. Debe establecer los atributos de texto predeterminados y los atributos de escritura. Establece los atributos de texto predeterminados cuando crea el campo de texto. Los atributos de escritura que debe establecer en el delegado. Si también está utilizando un marcador de posición, también querrá establecerlo en el mismo margen. En conjunto, obtienes algo como esto.

Primero crea una categoría en la UITextFieldclase.

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

Luego, si está utilizando marcadores colocados, asegúrese de usar un marcador de posición atribuido que establezca la misma sangría. Cree un diccionario con atributos predeterminados con los atributos adecuados, algo como esto:

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

Luego, importe la categoría anterior y cada vez que cree un campo de texto establezca la sangría predeterminada, el delegado y use los atributos de marcador de posición predeterminados definidos anteriormente. Por ejemplo:

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

Por último, en el delegado, implemente el textFieldDidBeginEditingmétodo, algo como esto:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    textField.indent = 7;
}
usuario3878720
fuente
La suposición que defaultTextAttributescontiene NSMutableParagraphStylees bastante peligrosa. Prefiero mutable Copiar todo esto.
Ben Sinclair
1

Normalmente trato de evitar las subclases, pero esto funciona si ya tienes:

// 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
fuente
¿Alguna razón por la que evitas las subclases? Que es un paradigma de diseño válido.
Aturdidor el
1

Para agregar otra solución que no necesita subclases:

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];

UITextField original UITextField fijo

Probado con iOS 7 y iOS 8. Ambos funcionan. Aún así, podría existir la posibilidad de que Apple modifique la jerarquía de capas de UITextField y arruine las cosas.

TheGrumpyCoda
fuente
1

Aquí hay una respuesta completa de Swift que incluye un LeftView (icono personalizado) y un botón de borrado personalizado, ambos configurados en Interface Builder con inserciones personalizables.

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
fuente
1

Una solución que realmente funciona y cubre todos los casos:

  • Debería usar offsetByno insetBy.
  • También debe llamar a la función super para obtener el original Rect.
  • Los límites son defectuosos. necesita compensar los X, Y originales. Los límites tienen X, Y como ceros.
  • Original x, y puede ser distinto de cero, por ejemplo, cuando se configura el leftView del UITextField.

Muestra:

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
fuente
0

Si desea cambiar la sangría SUPERIOR e IZQUIERDA solo entonces

// posición del marcador de posición

- (CGRect)textRectForBounds:(CGRect)bounds {

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

// posición del texto

- (CGRect)editingRectForBounds:(CGRect)bounds {

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

Solución rápida sin subclase y también inspeccionable

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