it-swarm.com.ru

Текстовая вставка для UITextField?

Я хотел бы вставить текст UITextField

Это возможно?

377
RunLoop

Переопределение -textRectForBounds: изменит только вставку текста заполнителя. Чтобы изменить вставку редактируемого текста, вам также необходимо переопределить -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

Я смог сделать это через:

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

Конечно, не забудьте импортировать QuartzCore, а также добавить Framework в ваш проект.

287
chuthan20

В классе, производном от UITextField, переопределите по крайней мере эти два метода:

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

Это может быть так просто, если у вас нет дополнительного контента:

return CGRectInset(bounds , 10, 10);

UITextField предоставляет несколько методов позиционирования, которые вы можете переопределить.

164
drawnonward

Если вам нужен только левый край, вы можете попробовать это:

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;

Меня устраивает. Я надеюсь, что это может помочь.

155
roberto.buratti

Как насчет класса @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)
    }
}

Вы увидите это в своей раскадровке.

enter image description here

Обновление - 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

Если у вас есть кнопка очистки, принятый ответ не будет работать для вас. Мы также должны остерегаться того, чтобы Apple изменила ситуацию в будущем, позвонив super.

Итак, чтобы убедиться, что текст не перекрывает кнопку очистки, давайте сначала получим значение «по умолчанию» из super, а затем скорректируем при необходимости.

Этот код добавит вставки размером 10px сверху, слева и снизу текстового поля:

@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

Примечание: UIEdgeInsetsMake принимает параметры в следующем порядке: верхний , левый , нижний , правый .

27
Chris Nolet

Думал, я бы поставил быстрое решение

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

Использование textRectForBounds: - правильный подход. Я обернул это в моем подклассе, чтобы вы могли просто использовать textEdgeInsets. Смотрите SSTextField .

14
Sam Soffes

Хороший подход для добавления отступов к UITextField - это создать подкласс UITextField и добавить свойство edgeInsets. Затем вы устанавливаете edgeInsets, и UITextField будет отображаться соответственно. Это также будет работать правильно с пользовательским набором leftView или 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
11
Brody Robertson

Вы можете установить текстовую вставку для UITextField, установив leftView. 

Как это: 

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

Для людей, которые ищут более простое решение. 

Добавьте UITextField внутри UIView. Чтобы имитировать вставку вокруг текстового поля, я оставляю 10 пикселей влево, а ширина на 20 пикселей меньше, чем у вида. Для закругленной угловой границы вокруг текстового поля используйте границу представления 

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

Свифт

    // 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 для Xcode 8.3.1 по состоянию на май 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/Разработан в Интерфейсном мастере/Раздельные горизонтальные и вертикальные насекомые/можно использовать из коробки

@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

&

 enter image description here

6
zgorawski

Вот тот же подкласс UITextField, написанный на Swift 3. Он довольно сильно отличается от предыдущих версий Swift, как вы увидите:

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

Кстати, вы также можете сделать что-то вроде следующего, если вы хотите контролировать вставку только одной стороны. Этот конкретный пример настройки только левой вставки полезен, если вы поместите изображение поверх UITextField, но вы хотите, чтобы оно отображалось пользователю в текстовом поле:

    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

Абсурдно, что вы должны создавать подклассы, так как UITextField уже реализует методы, как указывает @Adam Waite. Вот расширение Swift, которое предоставляет фабричный метод, также доступный в нашем репозитории 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
Christopher Pickslay

Вы можете настроить расположение текста в текстовом поле, сделав его подклассом UITextField и переопределив метод -textRectForBounds:.

3
Noah Witherspoon

Это самый быстрый способ, который я нашел без каких-либо подклассов:

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

В Свифте:

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

Это не так коротко, как в других примерах, но использует совершенно другой подход к решению этой проблемы. Обратите внимание, каретка по-прежнему будет заподлицо с левым краем, но при вводе/отображении текст будет иметь правильные отступы. Это работает без подклассов, если вы ищете только левое поле и вы уже используете UITextFieldDelegate для своих текстовых полей. Вам необходимо установить как текстовые атрибуты по умолчанию, так и атрибуты набора текста. Вы устанавливаете текстовые атрибуты по умолчанию при создании текстового поля. Атрибуты набора, которые необходимо установить в делегате. Если вы также используете местозаполнитель, вы также можете установить его на то же поле. В целом, вы получите что-то вроде этого.

Сначала создайте категорию в классе 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

Затем, если вы используете размещенные держатели, убедитесь, что вы используете атрибут-заполнитель с тем же отступом. Создайте атрибутивный словарь по умолчанию с правильными атрибутами, примерно так:

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

Затем импортируйте указанную выше категорию и всякий раз, когда вы создаете текстовое поле, задайте отступ по умолчанию, делегируйте и используйте атрибуты заполнителя по умолчанию, определенные выше. Например:

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

Наконец, в делегате реализуйте метод textFieldDidBeginEditing, что-то вроде этого:

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

Я поместил UITextField в подпункт, чтобы справиться с этим, который поддерживает левую, верхнюю, правую и нижнюю вставку, а также четкое позиционирование кнопок.

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

Пример использования, где * _someTextField * происходит из nib/раскадровки с MRDInsetTextField custom class

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

Я сделал это в IB, где я создал UIView позади textView, который был немного длиннее. С цветом фона textField, установленным, чтобы очистить .  enter image description here

2
jeremy wilson

Чтобы добавить другое решение, которое не требует подклассов:

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

Протестировано с iOS 7 и iOS 8. Оба работают. Тем не менее, есть вероятность, что Apple изменит иерархию слоев UITextField, что испортит ситуацию.

1
Lukas

Вот полный ответ Swift, который включает в себя leftView (пользовательский значок) и пользовательскую кнопку очистки, которые устанавливаются в Interface Builder с настраиваемыми вставками.

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

Я обычно стараюсь избегать подклассов, но это работает, если у вас уже есть:

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

Если вы хотите изменить отступ TOP и LEFT только тогда 

// позиция заполнителя

- (CGRect)textRectForBounds:(CGRect)bounds {

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

// текстовая позиция

- (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 версия:

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

Быстрое решение без подкласса и также проверяемое

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