web-dev-qa-db-fra.com

Texte inséré pour UITextField?

Je voudrais insérer le texte d'un UITextField

Est-ce possible?

377
RunLoop

Remplacer -textRectForBounds: ne modifiera que l'encart du texte de substitution. Pour changer l'encart du texte éditable, vous devez également remplacer -editingRectForBounds:.

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

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

J'ai pu le faire à travers:

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

Bien sûr, n'oubliez pas d'importer QuartzCore et d'ajouter également le Framework à votre projet.

287
chuthan20

Dans une classe dérivée de UITextField, substituez au moins ces deux méthodes:

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

Cela pourrait être aussi simple que cela si vous n'avez pas de contenu supplémentaire:

return CGRectInset(bounds , 10, 10);

UITextField fournit plusieurs méthodes de positionnement que vous pouvez remplacer.

164
drawnonward

Si vous avez juste besoin d'une marge gauche, vous pouvez essayer ceci:

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;

Ça marche pour moi. J'espère que cela peut aider.

155
roberto.buratti

Que diriez-vous d'une classe @IBInspectable, @IBDesignable Swift.

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

Vous verrez cela dans votre story-board.

enter image description here

Mise à jour - 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)
    }
}
87
mash

Si vous avez un bouton en clair, la réponse acceptée ne fonctionnera pas pour vous. Nous devrions également nous garder que Apple change les choses à l'avenir en appelant super.

Donc, pour vous assurer que le texte ne chevauche pas le bouton vide, obtenons d'abord la valeur 'par défaut' de super, puis ajustons-la si nécessaire.

Ce code ajoutera un encart de 10 pixels en haut, à gauche et en bas du champ de texte:

@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

Remarque: UIEdgeInsetsMake prend les paramètres dans l'ordre suivant: top , left , bottom , right .

27
Chris Nolet

Je pensais fournir une solution rapide

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

Utiliser textRectForBounds: est la bonne approche. J'ai résumé cela dans ma sous-classe afin que vous puissiez simplement utiliser textEdgeInsets. Voir SSTextField .

14
Sam Soffes

Une bonne approche pour ajouter du remplissage à UITextField consiste à sous-classer UITextField et à ajouter une propriété edgeInsets. Vous définissez ensuite les EdgeInsets et le UITextField sera dessiné en conséquence. Cela fonctionnera également correctement avec un ensemble leftView ou rightView personnalisé.

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
11
Brody Robertson

Vous pouvez définir un encadré de texte pour UITextField en définissant le paramètre leftView. 

Comme ça: 

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;
11
Golden

Pour les personnes qui recherchent une solution plus simple. 

Ajoutez la UITextField dans une UIView. Pour simuler un encart autour du champ de texte, il me reste 10 px et la largeur est 20px inférieure à la vue. Pour une bordure d'angle arrondie autour du champ de texte, utilisez la bordure de la vue. 

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

Rapide

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

Swift 3 Version pour Xcode 8.3.1 à partir de mai 2017:  

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

Swift 3/Designable dans Interface Builder/Insectes horizontaux et verticaux séparés/utilisable tel quel

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

usage:

 usage

Et

 enter image description here

6
zgorawski

Voici le même sous-groupe UITextField écrit dans Swift 3. Il est assez différent des versions précédentes de Swift, comme vous le verrez:

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

Incidemment, vous pouvez également procéder de la manière suivante si vous souhaitez contrôler l’encart d’un seul côté. Cet exemple particulier d'ajustement de l'encart gauche uniquement est pratique si vous placez une image au-dessus de UITextField mais que vous souhaitez qu'elle apparaisse à l'utilisateur dans le champ de texte:

    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
Gene Loparco

Il est absurde de sous-classer, car UITextField implémente déjà les méthodes, comme le souligne @Adam Waite. Voici une extension Swift qui expose une méthode d'usine, également disponible dans notre dépôt categories :

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

}
3

Vous pouvez ajuster le positionnement du texte dans un champ de texte en le transformant en une sous-classe de UITextField et en remplaçant la méthode -textRectForBounds:.

3
Noah Witherspoon

C'est le moyen le plus rapide que j'ai trouvé sans faire aucune sous-classe:

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

En rapide:

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

Ce n'est pas aussi court que les autres exemples, mais adopte une approche totalement différente pour résoudre ce problème. Remarque: le curseur d'insertion commencera quand même à affleurer le bord gauche, mais le texte sera correctement mis en retrait lorsqu'il sera tapé/affiché. Cela fonctionne sans sous-classement si vous recherchez uniquement une marge de gauche et que vous utilisez déjà UITextFieldDelegate pour vos champs de texte. Vous devez définir à la fois les attributs de texte par défaut et les attributs de frappe. Vous définissez les attributs de texte par défaut lorsque vous créez le champ de texte. Les attributs de frappe que vous devez définir dans le délégué. Si vous utilisez également un espace réservé, vous souhaiterez également le définir sur la même marge. En résumé, vous obtenez quelque chose comme ça.

Commencez par créer une catégorie dans la classe UITextField

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

Ensuite, si vous utilisez des supports placés, veillez à utiliser un espace réservé attribué définissant le même retrait. Créez un dictionnaire attribué par défaut avec les attributs appropriés, quelque chose comme ceci:

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

Importez ensuite la catégorie ci-dessus et, chaque fois que vous créez un champ de texte, définissez le retrait par défaut, le délégué et utilisez les attributs d'espace réservé par défaut définis ci-dessus. Par exemple:

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

Enfin, dans le délégué, implémentez la méthode textFieldDidBeginEditing, comme ceci:

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

J'ai sous-base UITextField pour gérer cela qui prend en charge les insertions gauche, supérieure, droite et inférieure, ainsi que le positionnement des boutons clairs.

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

Exemple d'utilisation où * _someTextField * provient de la vue nib/storyboard avec MRDInsetTextField custom class

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

Je l'ai fait dans IB où j'ai créé un UIView Behind the textView un peu plus long. Avec la couleur d'arrière-plan textField définie pour effacer .  enter image description here

2
jeremy wilson

Pour ajouter une autre solution qui n’a pas besoin de sous-classement:

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

Testé avec iOS 7 et iOS 8. Les deux fonctionnent. Néanmoins, Apple pourrait peut-être modifier la hiérarchie des couches de UITextField en gâchant tout.

1
Lukas

Voici une réponse Swift complète comprenant une leftView (icône personnalisée) et un bouton de suppression personnalisé, tous deux définis dans Interface Builder avec des encarts personnalisables.

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
rmooney

J'essaie normalement d'éviter les sous-classes mais cela fonctionne si vous avez déjà:

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

Si vous voulez modifier le retrait TOP et LEFT, alors seulement 

// emplacement réservé

- (CGRect)textRectForBounds:(CGRect)bounds {

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

// position du texte

- (CGRect)editingRectForBounds:(CGRect)bounds {

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

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

}
0
Bruno Paulino

Solution rapide sans sous-classe et également inspectable

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