Den Text in ein UITextField einrücken

77

Meine Frage ist so einfach wie der Titel, aber hier ist ein bisschen mehr:

Ich habe ein UITextField, auf dem ich das Hintergrundbild festgelegt habe. Das Problem ist, dass sich der Text so eng an den Rand schmiegt, der auch der Rand des Bildes ist. Ich möchte, dass mein Textfeld wie das von Apple aussieht, mit etwas horizontalem Abstand zwischen dem Hintergrundbild und dem Beginn des Textes.

Dyldo42
quelle
1
Wollen Sie die Einfügungen des Textes festlegen? Dann versuchen Sie diese Frage: stackoverflow.com/questions/2694411/text-inset-for-uitextfield
phi
Sie können eine UIImageView mit dem Bild hinzufügen, das Textfeld darüber hinzufügen und die Breite des Textfelds entsprechend einstellen ... das ist die einfachste Lösung ...
Swapnil Luktuke
@lukya Es sei denn, er möchte, dass der tippbare Bereich des Textfelds den Abschnitt mit dem Bild enthält. In diesem Fall erfordert Ihr Ansatz einen zusätzlichen Gestenerkenner und Code, damit er funktioniert.
Mark Amery

Antworten:

233

Dies ist der schnellste Weg, den ich gefunden habe, ohne Unterklassen zu erstellen:

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
adjwilli
quelle
18
Dies ist sauberer als die Unterklasse und behandelt die CLEAR-Taste korrekt. Ich wünschte, ich könnte +2 geben.
Rembrandt Q. Einstein
8
Ich stimme zu, +2 wenn ich könnte. Sobald ich in der vielfach abgestimmten Antwort 'Unterklasse' las, stöhnte ich innerlich, weil es immer schwieriger und fehleranfälliger ist, mit Zeichenmethoden zu täuschen
mblackwell8
6
Tolle Lösung, habe dies gerade in Swift übersetzt: var spacerView = UIView(frame:CGRect(x:0, y:0, width:10, height:10)); textfield.leftViewMode = UITextFieldViewMode.Always textfield.leftView = spacerView
Juliensaad
2
@jsiodtb Ich habe versucht, dies in Swift zu verwenden, aber es verhindert, dass mein Segue ausgeführt wird. Irgendeine Idee warum? Ich bin nannte es in viewDidLoad(). Es funktioniert auch nicht viewWillAppear().
IIllIIll
1
@Arcrammer Sie dürfen nicht dieselbe Ansicht wie zweimaliges Auffüllen verwenden (was den von Ihnen beschriebenen Fehler verursacht)
Norman
41

Sie müssen textRectForBounds: und editRectForBounds: unterordnen und überschreiben. Hier ist eine UITextfield-Unterklasse mit benutzerdefiniertem Hintergrund und vertikaler und horizontaler Auffüllung:

@interface MyUITextField : UITextField 
@property (nonatomic, assign) float verticalPadding;
@property (nonatomic, assign) float horizontalPadding;
@end

#import "MyUITextField.h"
@implementation MyUITextField
@synthesize horizontalPadding, verticalPadding;
- (CGRect)textRectForBounds:(CGRect)bounds {
    return CGRectMake(bounds.origin.x + horizontalPadding, bounds.origin.y + verticalPadding, bounds.size.width - horizontalPadding*2, bounds.size.height - verticalPadding*2);
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
    return [self textRectForBounds:bounds];
}
@end

Verwendung:

UIImage *bg = [UIImage imageNamed:@"textfield.png"];
CGRect rect = CGRectMake(0, 0, bg.size.width, bg.size.height);
MyUITextField *textfield = [[[MyUITextField alloc] initWithFrame:rect] autorelease];
textfield.verticalPadding = 10; 
textfield.horizontalPadding = 10;
[textfield setBackground:bg];
[textfield setBorderStyle:UITextBorderStyleNone];
[self.view addSubview:textfield];
Jano
quelle
1
Das ist eine gute Lösung, berücksichtigt aber nicht die Schaltfläche Löschen, wenn sie sichtbar ist. +1 trotzdem.
Jweyrich
Tolle Lösung! Ich kann nicht glauben, dass Apple es Ihnen nicht erlaubt, Einfügungen für UITextField festzulegen!
RPM
@RPM Da iOS 6.0 UITextView über eine AttributText-Eigenschaft verfügt, können Sie NSAttributedString mit den Attributen NSMutableParagraphStyle + firstLineHeadIndent (und tailIndent für die Schaltfläche zum Löschen) festlegen. Aber ja, es dauert iOS 6.
Jano
Aus irgendeinem Grund scheint firstLineHeadIndent in NSParagraphStyle keine Auswirkung auf die Art und Weise zu haben, wie Text in einem UITextField in iOS 6 angezeigt wird.
William Jockusch
26

Ein guter Ansatz zum Hinzufügen von Auffüllungen zu UITextField besteht darin, UITextField in Unterklassen zu unterteilen, die Rechteckmethoden zu überschreiben und eine edgeInsets-Eigenschaft hinzuzufügen. Sie können dann die edgeInsets festlegen und das UITextField wird entsprechend gezeichnet. Dies funktioniert auch mit einem benutzerdefinierten leftView- oder rightView-Set ordnungsgemäß.

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
quelle
Guter und sauberer Ansatz. Nur für andere, die diesen Kommentar lesen: Es besteht die Versuchung, mit spaceView zu gehen und leftView für die Textansicht zuzuweisen. Wenn Sie jedoch viele Textfelder haben, werden Sie den Code ringsum duplizieren, indem Sie spaceViews zu Ihrem gesamten Textfeld hinzufügen? Wahrscheinlich nein, also gehen Sie zu dieser Unterbesetzung, wenn Sie viele Textfelder haben.
Centurion
3
Ordentliche Lösung. +1 dafür UIEdgeInsetsist definitiv das passende Werkzeug für die jeweilige Aufgabe!
t6d
Dies funktioniert, ich fand die akzeptierte Antwort auf einen Absturz, wenn diese UITextFields Autolayout verwendeten.
Elliotrock
Viel sauberer als die am meisten gewählte Antwort, IMO. Gute Arbeit.
Brian Sachetta
Ich habe die anderen Lösungen ausprobiert, sie haben auch funktioniert, aber textRectForBounds ist der richtige Weg. Danke Brody.
Seymatanoglu
13

Ich habe daraus eine nette kleine Erweiterung für Storyboards gemacht:

public extension UITextField {
    @IBInspectable public var leftSpacer:CGFloat {
        get {
            return leftView?.frame.size.width ?? 0
        } set {
            leftViewMode = .Always
            leftView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))
        }
    }
}
Oxcug
quelle
1
Dieser funktioniert perfekt. Wenn Sie es mit @IBDesignable verwenden, können Sie es im Storyboard sehen
anasaitali
4

Meine 2 Cent:

class PaddedTextField : UITextField {
    var insets = UIEdgeInsets.zero
    var verticalPadding:CGFloat = 0
    var horizontalPadding:CGFloat = 0

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return CGRect(x: bounds.origin.x + insets.left, y: bounds.origin.y + insets.top, width: bounds.size.width - (insets.left + insets.right), height: bounds.size.height - (insets.top + insets.bottom));
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return textRect(forBounds: bounds)
    }
}
Chris Prince
quelle
1

Ich schlage vor, Ihre UITextFieldin a umzuwandeln UITextViewund die einzustellen contentInset. Zum Beispiel um 10 Leerzeichen einrücken:

textview.contentInset=UIEdgeInsetsMake(0, 10, 0, 0);
user790072
quelle
Dies ist eigentlich eine gute Lösung, nicht sicher, warum es abgelehnt wurde.
Jeremie D
2
@ Jeremy ist es, weil dies die Frage nicht beantwortet. UITextField und UITextView verhalten sich unterschiedlich und Sie müssten die Textansicht erheblich ändern, damit sie sich wie ein Textfeld verhält
Chris
0

Manchmal ist die linke Ansicht des Textfelds das Lupenbild eines Apple. In diesem Fall können Sie einen Einzug wie folgt festlegen:

    UIView *leftView = textField.leftView;
    if (leftView && [leftView isKindOfClass:[UIImageView class]]) {
        leftView.contentMode = UIViewContentModeCenter;
        leftView.width = 20.0f;  //the space you want indented.
    }
Lirik
quelle
0

Wenn Sie @ IBOutlet's nicht erstellen möchten, können Sie einfach eine Unterklasse erstellen (Antwort in Swift):

class PaddedTextField: UITextField {

  override func awakeFromNib() {
      super.awakeFromNib()

      let spacerView = UIView(frame:CGRect(x: 0, y: 0, width: 10, height: 10))
      leftViewMode = .always
      leftView = spacerView
   }
}
Vrutin Rathod
quelle