Texteinfügung für UITextField?

Antworten:

628

Durch das Überschreiben -textRectForBounds:wird nur der Einschub des Platzhaltertextes geändert. Um den Einschub des bearbeitbaren Textes zu ändern, müssen Sie auch überschreiben-editingRectForBounds:

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

// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
     return CGRectInset(bounds, 10, 10);
}
Azdev
quelle
10
Diese Lösung hat bei mir funktioniert, obwohl ich einen Rückgabewert von CGRectInset (bounds, 9, 0) verwendet habe. Ich musste diesen Wert auch für textRectForBounds, editRectForBounds und placeholderRectForBounds festlegen.
RyJ
2
Diese Lösung funktioniert mit clearButton nicht gut. Text innerhalb der TextField-Überlagerungsschaltfläche.
Piotr
Ich denke, das Überschreiben der oben genannten Methoden führt zu einem langsamen Bildlauf, wenn UITextFieldes sich innerhalb von a befindet UIScrollView.
Bharat Dodeja
2
Zum Platzieren des ClearButton: - (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); } Hier zu finden: stackoverflow.com/questions/5361369/…
Miros
22
Ich schlage vor, [super textRectForBounds: bounds] und [super editRectForBounds: bounds] aufzurufen, bevor CGRectInset (bounds, 10, 10) aufgerufen wird. Dadurch wird das Problem beim Löschen der Schaltflächenüberlagerung behoben.
Mrvincenzo
294

Ich konnte es schaffen durch:

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

Denken Sie natürlich daran, QuartzCore zu importieren und das Framework zu Ihrem Projekt hinzuzufügen.

chuthan20
quelle
38
+1 für Kreativität, aber das ist ein bisschen problematisch, es bewegt sich auch Löschknopf innerhalb des Textfeldes
Nikita
2
Sie könnten myTextField.layer.sublayers ausführen, das ein Array aller Unterschichten ist ... und wenn es UIImageView <ist - ich gehe davon aus, dass das X ein Bild ist ... oder vielleicht UIButton ... oder Sie könnten jedes einzelne durchlaufen und sehen welches zu welcher Unteransicht gehört ... aber myfield.layer.sublayerTransform alle Unterschichten und damit auch die sich bewegende X-Taste ..
chuthan20
Diese Lösung funktioniert bei mir nicht. Ich kann nur den linken und oberen Rand einstellen, aber nicht den rechten und unteren. UITextFieldÜberlappt den Inhalt auf der rechten Seite.
Bharat Dodeja
2
Dies ist die beste Lösung ohne Unterklassen und erfordert keine zusätzlichen, unnötigen Ansichten, um auf dem Bildschirm platziert zu werden! +1!
Rambatino
1
@ jeet.chanchawat Die X-Schaltfläche auf der rechten Seite in diesem Bild .. developer.apple.com/library/content/documentation/…
chuthan20
169

Wenn Sie nur einen linken Rand benötigen, können Sie Folgendes versuchen:

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;

Für mich geht das. Ich hoffe das kann helfen.

roberto.buratti
quelle
17
Dies ist weitaus einfacher als eine Unterklasse, nur um einen Einschub zu erhalten, und Sie können eine beliebige Ansicht auf der linken Seite hinzufügen (Sie können auch rightView verwenden, um etwas auf der rechten Seite zu platzieren). Besser als die akzeptierte Antwort IMHO.
Kenny Grant
4
+1 einfach, ohne Unterklassen und für die Arbeit mit Textfeldeigenschaften (anstatt "Hacken") ausgelegt.
Also drüber
Die dritte Zeile sollte sein leftView.backgroundColor = textField.backgroundColor;... Abgesehen von dieser großartigen Lösung ... Danke (:
Aviel Gross
Nicht ganz so elegant / gründlich wie Azdevs Antwort, aber eine großartige Lösung für einen gemeinsamen und einfachen Fall!
Rembrandt Q. Einstein
1
Durch Unterklassen sparen Sie eine Menge Zeit bei dieser Antwort, es sei denn, Sie haben ein einziges Textfeld, für das Sie dies benötigen.
Crake
168

Überschreiben Sie in einer von UITextField abgeleiteten Klasse mindestens diese beiden Methoden:

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

Es könnte so einfach sein, wenn Sie keinen zusätzlichen Inhalt haben:

return CGRectInset(bounds , 10, 10);

UITextField bietet verschiedene Positionierungsmethoden, die Sie überschreiben können.

nach vorne gezogen
quelle
2
Ja, wenn Sie editingRectForBounds nicht überschreiben, erhalten Sie den Text beim Bearbeiten oben links im Textfeld. - (CGRect) editRectForBounds: (CGRect) bounds {return CGRectInset (bounds, 10, 10); }
Mark W
1
Bearbeiten Sie einfach die Antwort, um die Methode
editRectForBounds
5
Dies scheint mir ein schrecklicher Hack - Sie müssten auch überschreiben- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
Zorayr
97

Wie über eine @IBInspectable, @IBDesignableschnelle Klasse.

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

Sie sehen dies in Ihrem Storyboard.

Geben Sie hier die Bildbeschreibung ein

Update - 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)
    }
}
Maische
quelle
1
Ich fand den Effekt auf Y unerwünscht. Ich möchte das Rechteck für den Text nicht verkleinern, sondern es in Richtung der Grundlinie des Feldes verschieben. Ich habe die Implementierungen angepasst anlet rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
Chris Wagner
1
Und fügen Sie dies auch hinzu, wenn Sie den Platzhalter `override func placeholderRectForBounds (Grenzen: CGRect) -> CGRect {return CGRectInset (Grenzen, insetX, insetY)}`
RameshVel
Seltsamerweise wirkt sich dies (Einstellen der Einfügungen in textRect/ editingRect) auf die Bildlaufleistung aus (zumindest unter iOS 12), wenn der Text über das sichtbare Rechteck hinausläuft. Mit einem Einschub von 15 hört es sogar auf zu scrollen.
Ixx
29

Wenn Sie eine Schaltfläche zum Löschen haben, funktioniert die akzeptierte Antwort für Sie nicht. Wir sollten uns auch davor schützen, dass Apple in Zukunft etwas ändert, indem wir anrufensuper .

Um sicherzustellen, dass der Text die Schaltfläche zum Löschen nicht überlappt, müssen Sie zuerst den Standardwert ermitteln superund dann nach Bedarf anpassen.

Dieser Code fügt oben, links und unten im Textfeld 10px-Einfügungen hinzu:

@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

Hinweis: UIEdgeInsetsMake akzeptiert Parameter in der Reihenfolge: oben , links , unten , rechts .

Chris Nolet
quelle
Verwenden textRectForBounds:und editingRectForBounds:Methoden ohne clearButtonRectForBounds: iOS 7+ haben bei mir funktioniert.
Stunner
clearButtonRectForBounds:hilft nur, den Löschknopf ein wenig nach links zu bewegen. Vielleicht möchten Sie es weglassen. Mein Textfeld befand sich auf einem dunklen Hintergrund, und für die Schaltfläche zum Löschen war rechts eine zusätzliche Polsterung erforderlich.
Chris Nolet
Seltsamerweise wirkt sich dies auf die Bildlaufleistung aus (zumindest unter iOS 12), wenn der Text über das sichtbare Rechteck hinausläuft. Mit einem Einschub von 15 hört es sogar auf zu scrollen.
Ixx
22

Ich dachte, ich würde eine schnelle Lösung liefern

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
quelle
2
Vergessen Sie nicht override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
Eugene Braginets
In Swift 3 müssen Sie die Methode 'CGRect.insetBy ()' verwenden
Den
1
Zumindest in iOS 11 textRectForBoundsist der Platzhalter ebenfalls betroffen , wenn Sie ihn überschreiben. Wenn Sie also den Platzhalter überschreiben, wird der Platzhalter um weitere 10 Punkte erweitert. Wenn es das ist, wonach Sie suchen, 👍🏼, aber wenn nicht, ist es gut, sich dessen bewusst zu sein.
DesignatedNerd
Seltsamerweise wirkt sich dies auf die Bildlaufleistung aus (zumindest unter iOS 12), wenn der Text über das sichtbare Rechteck hinausläuft. Mit einem Einschub von 15 hört es sogar auf zu scrollen.
Ixx
14

Verwenden textRectForBounds:ist der richtige Ansatz. Ich habe dies in meiner Unterklasse zusammengefasst, damit Sie es einfach verwenden können textEdgeInsets. Siehe SSTextField .

Sam Soffes
quelle
Dieser Ansatz funktioniert zusammen mit der Verwendung von Cocoapods zum Importieren des SSToolkit-Pods hervorragend - ich denke, dies ist der beste Weg.
Chris
Danke Chris! Ich bin froh, dass du es nützlich fandest.
Sam Soffes
14

Schnell

 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
quelle
Seltsamerweise wirkt sich dies auf die Bildlaufleistung aus (zumindest unter iOS 12), wenn der Text über das sichtbare Rechteck hinausläuft. Mit einem Einschub von 15 hört es sogar auf zu scrollen.
Ixx
12

Für Leute, die nach einer einfacheren Lösung suchen.

Fügen Sie das UITextFieldInnere hinzu a UIView. Um einen Einschub um ein Textfeld zu simulieren, halte ich 10 Pixel links und die Breite ist 20 Pixel kleiner als die Ansicht. Verwenden Sie für einen abgerundeten Eckrand um das Textfeld den Rand der Ansicht

viewBG.layer.cornerRadius = 8.0;
viewBG.layer.borderColor = [UIColor darkGrayColor].CGColor;
viewBG.layer.borderWidth = 1.0;
Karim
quelle
2
Ehrlich gesagt ist es die beste und einfachste Lösung, nur ein UIView hinter das UITextField zu stellen. Machen Sie das UITextField transparent und fertig. Ich habe es mit einem UITextView ausgerichtet - es stellt sich heraus, dass es ungefähr 6 Pixel eingelegt ist. Viel einfacher und auch flexibler als das Erstellen einer Unterklasse ...
n13
Ein Problem bei diesem Ansatz ist die Position, an der die Bildlaufleiste angezeigt wird.
Doug Amos
@DougAmos Welche Bildlaufleiste? Beziehen Sie sich UITextViewvielleicht?
Bedeutung-Angelegenheiten
12

Sie können die Texteinfügung für UITextField festlegen, indem Sie die linke Ansicht festlegen.

So was:

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;
Golden
quelle
1
Wenn Sie auch die linke Ansicht für ein Symbol verwenden müssen, kann dies nicht funktionieren
Reaper
@Reaper Diese Methode funktioniert auch für ein Bild. Fügen Sie der Breite des Bildansichtsrahmens die gewünschte Auffüllmenge hinzu und setzen Sie den Inhaltsmodus auf Mitte. imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
Andy
Das ist viel zu hackig. Es gibt bereits eine textRectForBounds-Methode zum Setzen des Einschubs
Gerald
12

Schnell

    // adjust place holder text
    let paddingView = UIView(frame: CGRectMake(0, 0, 10, usernameOrEmailField.frame.height))
    usernameOrEmailField.leftView = paddingView
    usernameOrEmailField.leftViewMode = UITextFieldViewMode.Always
LondonGuy
quelle
1
Dies ist eine wirklich billige und einfache Problemumgehung. Vielen Dank!
Shnaz
11

Ein guter Ansatz zum Hinzufügen von Auffüllungen zu UITextField besteht darin, UITextField in Unterklassen zu unterteilen und eine edgeInsets-Eigenschaft hinzuzufügen. Anschließend legen Sie die edgeInsets fest und das UITextField wird entsprechend gezeichnet. Dies funktioniert auch korrekt mit einem benutzerdefinierten leftView- oder rightView-Set.

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
Gute Antwort. Liefert das fehlende Eigentum :-)
Phatmann
6

Swift 3 / Designable in Interface Builder / Separate horizontale und vertikale Insekten / sofort einsatzbereit

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

Verwendungszweck:

Verwendungszweck

&

Geben Sie hier die Bildbeschreibung ein

zgorawski
quelle
5

Ich habe dies in IB gemacht, wo ich eine UIView hinter der TextView erstellt habe, die etwas länger war. Wenn die Hintergrundfarbe von textField auf klar eingestellt ist. Geben Sie hier die Bildbeschreibung ein

Jeremy Wilson
quelle
5

Es ist der schnellste Weg, den ich gefunden habe, ohne Unterklassen zu machen:

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
Max
quelle
4

Hier ist das gleiche UITextField der Unterklasse, das in Swift 3 geschrieben wurde. Es unterscheidet sich erheblich von früheren Versionen von Swift, wie Sie sehen werden:

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

Im Übrigen können Sie auch Folgendes tun, wenn Sie den Einschub nur einer Seite steuern möchten. Dieses spezielle Beispiel zum Anpassen nur des linken Einschubs ist nützlich, wenn Sie ein Bild über dem UITextField platzieren, es dem Benutzer jedoch im Textfeld anzeigen soll:

    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
quelle
4

Swift 4.2 Version:

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
quelle
Seltsamerweise wirkt sich dies auf die Bildlaufleistung aus (zumindest unter iOS 12), wenn der Text über das sichtbare Rechteck hinausläuft. Mit einem Einschub von 15 hört es sogar auf zu scrollen.
Ixx
3

Sie können die Position des Texts in einem Textfeld anpassen, indem Sie ihn zu einer Unterklasse UITextFieldder -textRectForBounds:Methode machen und diese überschreiben .

Noah Witherspoon
quelle
3

Es ist absurd, dass Sie eine Unterklasse bilden müssen, da UITextFielddie Methoden bereits implementiert sind, wie @Adam Waite betont. Hier ist eine schnelle Erweiterung, die eine Factory-Methode verfügbar macht, die auch in unseren Kategorien repo verfügbar ist :

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
quelle
Der Link in Ihrer Antwort ist tot. Können Sie ihn bitte aktualisieren?
WendiKidd
Die URL @WendiKidd
Christopher Pickslay wurde
2

Ich habe UITextField untergeordnet, um dies zu handhaben, das den linken, oberen, rechten und unteren Einschub sowie das Löschen der Tastenpositionierung unterstützt.

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

Anwendungsbeispiel, bei dem * _someTextField * aus der Nib / Storyboard-Ansicht mit der benutzerdefinierten MRDInsetTextField- Klasse stammt

[(MRDInsetTextField*)_someTextField setInset:CGRectMake(5, 0, 5, 0)]; // left, top, right, bottom inset
Firula
quelle
Vielen Dank. Ein Vorschlag für Ihren Code: Warum haben Sie CGRect für Inset und nicht für UIEdgeInsets verwendet?
Sha
2

Dies ist nicht so kurz wie die anderen Beispiele, verfolgt jedoch einen völlig anderen Ansatz zur Lösung dieses Problems. Beachten Sie, dass das Caret weiterhin bündig mit dem linken Rand beginnt, der Text jedoch beim Eingeben / Anzeigen ordnungsgemäß eingerückt wird. Dies funktioniert ohne Unterklassen, wenn Sie nur einen linken Rand suchen und ihn bereits UITextFieldDelegatefür Ihre Textfelder verwenden. Sie müssen sowohl die Standardtextattribute als auch die Typattribute festlegen. Sie legen die Standardtextattribute fest, wenn Sie das Textfeld erstellen. Die Typattribute, die Sie im Delegaten festlegen müssen. Wenn Sie auch einen Platzhalter verwenden, möchten Sie diesen ebenfalls auf den gleichen Rand setzen. Alles in allem erhalten Sie so etwas.

Erstellen Sie zunächst eine Kategorie für die UITextFieldKlasse.

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

Wenn Sie dann platzierte Halter verwenden, stellen Sie sicher, dass Sie einen zugewiesenen Platzhalter verwenden, der denselben Einzug setzt. Erstellen Sie ein Standardwörterbuch mit den richtigen Attributen:

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

Importieren Sie dann die obige Kategorie und legen Sie beim Erstellen eines Textfelds den Standardeinzug, den Delegaten und die oben definierten Standardplatzhalterattribute fest. Zum Beispiel:

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

Implementieren Sie schließlich im Delegaten die textFieldDidBeginEditingMethode wie folgt:

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
    textField.indent = 7;
}
user3878720
quelle
Die Annahme, die defaultTextAttributesenthält, NSMutableParagraphStyleist ziemlich gefährlich. Ich würde das alles lieber veränderlich kopieren.
Ben Sinclair
1

Normalerweise versuche ich, Unterklassen zu vermeiden, aber das funktioniert, wenn Sie bereits:

// 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
quelle
Gibt es einen Grund, warum Sie Unterklassen vermeiden? Es ist ein gültiges Design-Paradigma.
Stunner
1

So werfen Sie eine andere Lösung ein, für die keine Unterklassen erforderlich sind:

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 UITextField behoben

Getestet mit iOS 7 und iOS 8. Beide funktionieren. Dennoch besteht möglicherweise die Möglichkeit, dass Apple die Ebenenhierarchie von UITextField ändert, was die Dinge stark durcheinander bringt.

TheGrumpyCoda
quelle
1

Hier ist eine umfassende Swift-Antwort, die eine leftView (benutzerdefiniertes Symbol) und eine benutzerdefinierte Schaltfläche zum Löschen enthält, die beide im Interface Builder mit anpassbaren Einfügungen festgelegt sind.

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

}
Geld
quelle
1

Eine Lösung, die tatsächlich funktioniert und alle Fälle abdeckt:

  • Sollte offsetBynicht verwenden insetBy.
  • Sollte auch die Super-Funktion aufrufen, um das Original zu erhalten Rect.
  • Grenzen sind fehlerhaft. Sie müssen das ursprüngliche X, Y versetzen. Grenzen haben X, Y als Nullen.
  • Das ursprüngliche x, y kann beispielsweise ungleich Null sein, wenn die linke Ansicht des UITextField festgelegt wird.

Stichprobe:

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

Wenn Sie den Einzug oben und links nur dann ändern möchten

// Platzhalterposition

- (CGRect)textRectForBounds:(CGRect)bounds {

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

// Textposition

- (CGRect)editingRectForBounds:(CGRect)bounds {

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

Schnelle Lösung ohne Unterklasse und auch inspizierbar

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