Inserimento di testo per UITextField?


Risposte:


628

La -textRectForBounds:sostituzione cambierà solo l'inserimento del testo segnaposto. Per modificare l'inserimento del testo modificabile, è necessario eseguire anche l'override-editingRectForBounds:

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

// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
     return CGRectInset(bounds, 10, 10);
}

10
Questa soluzione ha funzionato per me, anche se ho usato un valore di ritorno di CGRectInset (limiti, 9, 0); Avevo anche bisogno di impostare questo valore per textRectForBounds, editingRectForBounds e placeholderRectForBounds.
RyJ,

2
Questa soluzione non funziona bene con clearButton. Testo all'interno del pulsante di sovrapposizione di TextField.
Piotr,

Penso che, sovrascrivendo i metodi sopra, lo scorrimento rallenti, se UITextFieldrisiede in a UIScrollView.
Bharat Dodeja

2
Per posizionare il ClearButton: - (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); } Trovato qui: stackoverflow.com/questions/5361369/...
Miros

22
Suggerisco di chiamare [super textRectForBounds: bounds] e [super editingRectForBounds: bounds] prima di chiamare CGRectInset (bounds, 10, 10). Ciò risolverà il problema di sovrapposizione del pulsante Cancella.
mrvincenzo,

294

Sono stato in grado di farlo attraverso:

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

Ovviamente ricordati di importare QuartzCore e di aggiungere anche il Framework al tuo progetto.


38
+1 per la creatività, ma questo è un po 'problematico, sposta anche il pulsante Elimina all'interno del campo di testo
Nikita,

2
potresti fare myTextField.layer.sublayers che è un array di tutti i sublayer ... e se il suo UIImageView <- suppongo che la X sia un'immagine ... o forse UIButton ... o potresti fare un ciclo completo di ognuno e vedere a quale appartiene a quale sottoview ... ma myfield.layer.sublayerTrasforma tutti i sublayer e quindi anche il pulsante X in movimento ..
chuthan20

Questa soluzione non funziona per me. Posso solo impostare il margine sinistro e superiore ma non quello destro e inferiore. UITextFieldsi sovrappone al contenuto sul lato destro di esso.
Bharat Dodeja

2
Questa è la soluzione migliore senza sottoclasse e non richiede di visualizzare sullo schermo viste extra non necessarie! +1!
Rambatino,

1
@ jeet.chanchawat Il pulsante X sul lato destro in questa immagine .. developer.apple.com/library/content/documentation/…
chuthan20

169

Se hai bisogno solo di un margine sinistro, puoi provare questo:

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;

Per me funziona. Spero che questo possa aiutare.


17
Questo è molto più facile della sottoclasse solo per ottenere un inserto e ti consente di aggiungere qualsiasi vista arbitraria a sinistra (puoi anche usare rightView per mettere qualcosa a destra). Meglio della risposta accettata IMHO.
Kenny Grant,

4
+1 facile, senza sottoclasse e progettato per funzionare con le proprietà dei campi di testo (piuttosto che "hacking").
So Over It

La terza riga dovrebbe essere leftView.backgroundColor = textField.backgroundColor;... A parte quella ottima soluzione ... Grazie (:
Aviel Gross

Non altrettanto elegante / completo come la risposta di Azdev, ma un'ottima soluzione per un caso comune e semplice!
Rembrandt Q. Einstein,

1
La sottoclasse ti farà risparmiare un sacco di tempo su questa risposta, a meno che tu non abbia una sola casella di testo per cui hai bisogno di questo.
Crake,

168

In una classe derivata da UITextField, sovrascrivi almeno questi due metodi:

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

Potrebbe essere così semplice se non hai contenuti aggiuntivi:

return CGRectInset(bounds , 10, 10);

UITextField offre diversi metodi di posizionamento che è possibile ignorare.


2
sì, se non si sovrascrive editingRectForBounds si ottiene il testo quando si modifica in alto a sinistra nel campo di testo. - (CGRect) editingRectForBounds: limiti (CGRect) {return CGRectInset (limiti, 10, 10); }
Mark W

1
Ho appena modificato la risposta per integrare il metodo editingRectForBounds in
ɾɾuǝʞ

5
Questo mi sembra un orribile trucco - dovresti anche scavalcare- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
Zorayr,

98

Come su un @IBInspectable, @IBDesignableclasse rapida.

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

Vedrai questo nel tuo storyboard.

inserisci qui la descrizione dell'immagine

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

1
Ho trovato l'effetto su Y indesiderato, non voglio ridurre la rettitudine per il testo, piuttosto spingerlo verso il basso verso la base del campo. Ho adattato le implementazioni alet rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
Chris Wagner il

1
E aggiungi anche questo se stai usando il segnaposto `override func placeholderRectForBounds (bounds: CGRect) -> CGRect {return CGRectInset (bounds, insetX, insetY)}`
RameshVel

Stranamente questo (l'impostazione degli inserti in textRect/ editingRect) influisce sulle prestazioni di scorrimento (almeno su iOS 12), quando il testo trabocca il rettangolo visibile. Con un inserto di 15 smette persino di scorrere.
Ixx,

29

Se hai un pulsante chiaro, la risposta accettata non funzionerà per te. Dovremmo anche evitare che Apple cambi le cose in futuro chiamando super.

Quindi, per assicurarci che il testo non si sovrapponga al pulsante Cancella, prendiamo prima il valore "predefinito" super, quindi aggiustiamo se necessario.

Questo codice aggiungerà un 10px inserti nella parte superiore, sinistra e inferiore del campo di testo:

@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 accetta i parametri nell'ordine: in alto , a sinistra , in basso , a destra .


L'uso textRectForBounds:e i editingRectForBounds:metodi senza clearButtonRectForBounds: iOS 7+ hanno funzionato per me.
Storditore,

clearButtonRectForBounds:aiuta solo a spostare leggermente il pulsante Clear a sinistra. Ti potrebbe piacere lasciarlo fuori. Il mio campo di testo era su uno sfondo scuro e il pulsante Cancella aveva bisogno di un po 'di imbottitura in più a destra.
Chris Nolet,

Stranamente questo influisce sulle prestazioni di scorrimento (almeno su iOS 12), quando il testo trabocca il rettangolo visibile. Con un inserto di 15 smette persino di scorrere.
Ixx,

22

Ho pensato di fornire una soluzione rapida

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

2
Non dimenticare override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
Eugene Braginets il

In Swift 3 devi usare il metodo 'CGRect.insetBy ()'
Den

1
Almeno in iOS 11, se si esegue textRectForBoundsl' override , anche il segnaposto è interessato, quindi l'aggiunta dell'override segnaposto inserisce il segnaposto un altro 10pt ulteriormente. Se è quello che stai cercando, 👍🏼, ma in caso contrario, è bene essere consapevoli.
Designato

Stranamente questo influisce sulle prestazioni di scorrimento (almeno su iOS 12), quando il testo trabocca il rettangolo visibile. Con un inserto di 15 smette persino di scorrere.
Ixx,

14

L'uso textRectForBounds:è l'approccio corretto. L'ho inserito nella mia sottoclasse in modo da poterlo semplicemente usare textEdgeInsets. Vedi SSTextField .


Questo approccio, insieme all'utilizzo di cocoapods per importare il pod SSToolkit, funziona benissimo - penso che questo sia il modo più semplice di procedere.
Chris

Grazie Chris! Mi fa piacere che l'abbia trovato utile.
Sam Soffes,

14

veloce

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

Stranamente questo influisce sulle prestazioni di scorrimento (almeno su iOS 12), quando il testo trabocca il rettangolo visibile. Con un inserto di 15 smette persino di scorrere.
Ixx,

12

Per le persone che cercano una soluzione più semplice.

Aggiungi l' UITextFieldinterno a UIView. Per simulare un riquadro attorno al campo di testo, rimango 10 px a sinistra e la larghezza è 20px in meno rispetto alla vista. Per un bordo dell'angolo arrotondato attorno al campo di testo, usa il bordo della vista

viewBG.layer.cornerRadius = 8.0;
viewBG.layer.borderColor = [UIColor darkGrayColor].CGColor;
viewBG.layer.borderWidth = 1.0;

2
Sinceramente mettere una UIView dietro UITextField è la soluzione migliore e più semplice. Rendi UITextField trasparente e fatto. L'ho allineato con un UITextView - risulta essere inserito a circa 6 pixel. Molto più facile e anche più flessibile della creazione di una sottoclasse ...
n13

Un problema con questo approccio è la posizione in cui apparirà la barra di scorrimento.
Doug Amos,

@DougAmos Che barra di scorrimento? Ti riferisci UITextViewforse?
significato-importa

12

È possibile impostare l'inserzione di testo per UITextField impostando leftView.

Come questo:

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;

1
Quando devi anche usare la vista a sinistra per un'icona, questo non può funzionare
Reaper

@Reaper questo metodo funzionerà anche per un'immagine. aggiungere la quantità di riempimento desiderata alla larghezza del riquadro della visualizzazione immagine e impostare la modalità contenuto al centro. imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
Andy,

questo è troppo confuso. esiste già un metodo textRectForBounds per impostare l'inser
Gerald

12

veloce

    // adjust place holder text
    let paddingView = UIView(frame: CGRectMake(0, 0, 10, usernameOrEmailField.frame.height))
    usernameOrEmailField.leftView = paddingView
    usernameOrEmailField.leftViewMode = UITextFieldViewMode.Always

1
Questa è una soluzione davvero economica e facile. Grazie!
shnaz,

11

Un buon approccio per aggiungere il riempimento a UITextField è la sottoclasse di UITextField e l'aggiunta di una proprietà edgeInsets. Quindi impostare edgeInsets e UITextField verrà disegnato di conseguenza. Funzionerà anche correttamente con un set personalizzato 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

Buona risposta. Fornisce la proprietà mancante :-)
Phatmann,

6

Swift 3 / Designable in Interface builder / Separati insetti orizzontali e verticali / utilizzabili immediatamente

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

utilizzo:

uso

&

inserisci qui la descrizione dell'immagine


5

L'ho fatto in IB dove ho creato un UIView Behind the textView che era un po 'più lungo. Con il colore di sfondo di textField impostato su clear. inserisci qui la descrizione dell'immagine


5

È il modo più rapido che ho trovato senza fare alcuna sottoclasse:

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

In Swift:

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

4

Ecco la stessa sottoclasse UITextField scritta in Swift 3. È abbastanza diversa dalle versioni precedenti di Swift, come vedrai:

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

Per inciso, puoi anche fare qualcosa di simile al seguente, se vuoi controllare l'inserzione di un solo lato. Questo esempio particolare di regolazione solo dell'inserzione di sinistra è utile se si posiziona un'immagine sopra UITextField ma si desidera che appaia all'utente all'interno del campo di testo:

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

4

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

}

Stranamente questo influisce sulle prestazioni di scorrimento (almeno su iOS 12), quando il testo trabocca il rettangolo visibile. Con un inserto di 15 smette persino di scorrere.
Ixx,

3

È possibile regolare il posizionamento del testo all'interno di un campo di testo rendendolo una sottoclasse UITextFielde sovrascrivendo il -textRectForBounds:metodo.


3

È assurdo dover sottoclassare, poiché UITextFieldimplementa già i metodi, come sottolinea @Adam Waite. Ecco una rapida estensione che espone un metodo factory, disponibile anche nel repository delle nostre categorie :

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

}

Il link nella tua risposta è morto, puoi aggiornarlo, per favore?
WendiKidd,

Risolto il problema con l'URL @WendiKidd
Christopher Pickslay,

2

Ho sottoclassato UITextField per gestire ciò che supporta l'inserimento a sinistra, in alto, a destra e in basso e anche il posizionamento dei pulsanti.

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

Esempio di utilizzo in cui * _someTextField * proviene dalla vista pennino / storyboard con la classe personalizzata MRDInsetTextField

[(MRDInsetTextField*)_someTextField setInset:CGRectMake(5, 0, 5, 0)]; // left, top, right, bottom inset

Grazie. Un suggerimento per il tuo codice però - perché hai usato CGRect per l'inser e non UIEdgeInsets?
sha

2

Questo non è breve come gli altri esempi, ma adotta un approccio completamente diverso per risolvere questo problema. Nota, il punto di inserimento inizierà comunque a filo con il bordo sinistro, ma il testo verrà rientrato correttamente quando digitato / visualizzato. Funziona senza sottoclasse se stai cercando solo un margine sinistro e stai già utilizzandoUITextFieldDelegate per i tuoi campi di testo. È necessario impostare sia gli attributi di testo predefiniti sia gli attributi di digitazione. Impostare gli attributi di testo predefiniti quando si crea il campo di testo. Gli attributi di digitazione che devi impostare nel delegato. Se stai usando anche un segnaposto, vorrai impostare anche quello sullo stesso margine. Mettendo tutto insieme ottieni qualcosa del genere.

Innanzitutto crea una categoria sulla 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

Quindi, se si utilizzano segnaposti posizionati assicurarsi di utilizzare un segnaposto attribuito impostando lo stesso rientro. Crea un dizionario attribuito predefinito con gli attributi corretti, qualcosa del genere:

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

Quindi, importa la categoria sopra e ogni volta che crei un campo di testo imposta il rientro predefinito, il delegato e usa gli attributi segnaposto predefiniti definiti sopra. Per esempio:

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

Infine, nel delegato, implementa il textFieldDidBeginEditingmetodo, qualcosa del genere:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    textField.indent = 7;
}

L'ipotesi che defaultTextAttributescontiene NSMutableParagraphStyleè piuttosto pericolosa .. Preferirei mutevole Copiare tutto questo.
Ben Sinclair,

1

Di solito cerco di evitare la sottoclasse ma questo funziona se hai già:

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

Qual è il motivo per cui eviti la sottoclasse? Si tratta di un paradigma di progettazione valida.
Storditore,

1

Per aggiungere un'altra soluzione che non richiede la sottoclasse:

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 originale Risolto UITextField

Testato con iOS 7 e iOS 8. Entrambi funzionanti. Tuttavia, potrebbe esserci la possibilità che Apple modifichi la gerarchia dei livelli di UITextField che rovini le cose male.


1

Ecco una risposta Swift completa che include un leftView (icona personalizzata) e un pulsante di cancellazione personalizzato, entrambi impostati in Interface Builder con inserti personalizzabili.

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

}

1

Una soluzione che funziona davvero e copre tutti i casi:

  • Dovranno utilizzare offsetBynon insetBy.
  • Dovrebbe anche chiamare la funzione super per ottenere l'originale Rect.
  • I limiti sono difettosi. devi compensare la X, Y originale. I limiti hanno X, Y come zeri.
  • L'originale x, y può essere diverso da zero, ad esempio quando si imposta la vista sinistra di UITextField.

Campione:

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

0

Se si desidera modificare il rientro TOP e LEFT solo allora

// posizione segnaposto

- (CGRect)textRectForBounds:(CGRect)bounds {

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

// posizione del testo

- (CGRect)editingRectForBounds:(CGRect)bounds {

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

-1

Soluzione rapida senza sottoclasse e anche ispezionabile

extension UITextField {
    @IBInspectable var textInsets: CGPoint {
            get {
                return CGPoint.zero
            }
            set {
                layer.sublayerTransform = CATransform3DMakeTranslation(newValue.x, newValue.y, 0);
            }
        }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.