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


Ответы:


628

Переопределение -textRectForBounds:только изменит вставку текста заполнителя. Чтобы изменить вставку редактируемого текста, необходимо также переопределить-editingRectForBounds:

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

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

10
Это решение работало для меня, хотя я использовал возвращаемое значение CGRectInset (bounds, 9, 0); Мне также нужно было установить это значение для textRectForBounds, editRectForBounds и placeholderRectForBounds.
— RyJ

2
Это решение не очень хорошо работает с clearButton. Текст внутри кнопки наложения TextField.
— Петр

Я думаю, что переопределение вышеуказанных методов вызовет медленную прокрутку, если UITextFieldнаходится внутри UIScrollView.
— Бхарат Додея

2
Для размещения ClearButton: - (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); } найдено здесь: stackoverflow.com/questions/5361369/…
— Miros

22
Я предлагаю вызвать [super textRectForBounds: bounds] и [super editRectForBounds: bounds] перед вызовом CGRectInset (bounds, 10, 10). Это исправит проблему с наложением кнопки очистки.
— Мрвинченцо

294

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

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

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


38
+1 за креативность, но это немного проблематично, движется и кнопка удаления внутри текстового поля
— Никита

2
вы могли бы сделать myTextField.layer.sublayers, который является массивом всех подслоев ... и если его UIImageView <- я предполагаю, что X является изображением ... или, может быть, UIButton ... или вы можете тщательно просмотреть каждый из них и посмотреть какой из них принадлежит какому подпредставлению ... но myfield.layer.sublayer преобразует все подслои и, таким образом, также перемещает кнопку X.
— chuthan20

Это решение не работает для меня. Я могу установить только левое и верхнее поле, но не правое и нижнее. UITextFieldперекрывает содержимое с правой стороны.
— Бхарат Додея

2
Это лучшее решение без подклассов и не требует дополнительных ненужных представлений для размещения на экране! +1!
— Рамбатино

1
@ jeet.chanchawat Кнопка X с правой стороны на этой картинке .. developer.apple.com/library/content/documentation/…
— chuthan20

169

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

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;

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


17
Это гораздо проще, чем создавать подклассы просто для того, чтобы получить вставку, и позволяет добавить любое произвольное представление слева (вы также можете использовать rightView, чтобы поместить что-то справа). Лучше принятого ответа ИМХО.
— Кенни Грант

4
+1 легко, без подклассов, и предназначен для работы со свойствами текстового поля (вместо «взлома»).
— Итак,

Третья строка должна быть leftView.backgroundColor = textField.backgroundColor;... Кроме этого отличного решения ... Спасибо (:
— Aviel Gross

Не такой элегантный / тщательный, как ответ Аздева, но отличное решение для простого и простого случая!
— Рембрандт Q. Эйнштейн

1
Подклассы сэкономят вам массу времени на этот ответ, если только у вас нет одного текстового поля, для которого это нужно.
— Crake

168

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

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

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

return CGRectInset(bounds , 10, 10);

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


2
да, если вы не переопределите editRectForBounds, вы получите текст при редактировании в левом верхнем углу текстового поля. - (CGRect) editRectForBounds: (CGRect) bounds {return CGRectInset (bounds, 10, 10); }
— Mark W

1
Только что отредактировал ответ, чтобы интегрировать метод editRectForBounds в
— ıǝʞuǝʞ

5
Это кажется мне ужасным взломом - вы также должны переопределить- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
— Зорайр

98

Как насчет @IBInspectable, @IBDesignableстремительный класс.

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

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

введите описание изображения здесь

Обновление - 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
Я обнаружил, что эффект на Y нежелателен, я не хочу сжимать прямоугольник для текста, а скорее подтолкну его к базовой линии поля. Я приспособил реализации кlet rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
— Крису Вагнеру

1
И добавьте это тоже, если вы используете заполнитель `override func placeholderRectForBounds (bounds: CGRect) -> CGRect {вернуть CGRectInset (bounds, insetX, insetY)}`
— RameshVel

Странно, но это (установка вставок в textRect/ editingRect) влияет на производительность прокрутки (по крайней мере, на iOS 12), когда текст выходит за видимый прямоугольник. При вставке 15 он даже перестает прокручиваться.
— Ixx

29

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

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

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

@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 принимает параметры в следующем порядке: сверху , слева , снизу , справа .


Использование textRectForBounds:и editingRectForBounds:методы без clearButtonRectForBounds: на iOS 7+ работали для меня.
— Stunner

clearButtonRectForBounds:просто помогает слегка подтолкнуть кнопку очистки влево. Вы можете оставить это. Мое текстовое поле было на темном фоне, а кнопка очистки нуждалась в небольшом дополнительном заполнении справа.
— Крис Нолет

Как ни странно, это влияет на производительность прокрутки (по крайней мере, на iOS 12), когда текст переполняет видимый прямоугольник. При вставке 15 он даже перестает прокручиваться.
— Ixx

22

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

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

Свифт 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
Не забывайте override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
— Евгений Брагинец

В Swift 3 вы должны использовать метод CGRect.insetBy ()
— Den

1
По крайней мере, в iOS 11, если вы переопределите textRectForBounds, заполнитель также будет затронут - так что добавление переопределенного заполнителя вставляет заполнитель еще на 10pt дальше. Если это то, что вы ищете, if, но если нет, то это полезно знать.
— DesignedNerd

Как ни странно, это влияет на производительность прокрутки (по крайней мере, на iOS 12), когда текст переполняет видимый прямоугольник. При вставке 15 он даже перестает прокручиваться.
— Ixx

14

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


Этот подход, наряду с использованием cocoapods для импорта пакета SSToolkit, прекрасно работает - я думаю, что это самый лучший способ.
— Крис

Спасибо Крис! Рад, что вы нашли это полезным.
— Сэм Соффс

14

стриж

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

Как ни странно, это влияет на производительность прокрутки (по крайней мере, на iOS 12), когда текст переполняет видимый прямоугольник. При вставке 15 он даже перестает прокручиваться.
— Ixx

12

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

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

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

2
Честно говоря, просто положить UIView за UITextField является лучшим и самым простым решением. Сделайте UITextField прозрачным и готовым. Я выровнял его с UITextView - получается около 6 пикселей. Гораздо проще, а также более гибко, чем создание подкласса ...
— n13

Проблема этого подхода заключается в расположении полосы прокрутки.
— Даг Амос

@DougAmos Какая полоса прокрутки? Вы имеете в виду, UITextViewвозможно?
— значение имеет значение

12

Вы можете установить текстовую вставку для 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;

1
Когда вам также нужно использовать вид слева для значка, это не работает
— Жнец

@ Reaper этот метод также будет работать для изображения. Добавьте желаемое количество отступов к ширине рамки просмотра изображения и установите режим контента в центр. imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
— Энди

это слишком глупо уже есть метод textRectForBounds для установки вставки
— Джеральд

12

стриж

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

1
Это действительно дешевый и простой обходной путь. Спасибо!
— Шназ

11

Хороший подход для добавления отступов в 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

Хороший ответ. Поставляет недостающее имущество :-)
— phatmann

6

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

Применение:

Применение

&

введите описание изображения здесь


5

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


5

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

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

4

Вот тот же подкласс 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

Версия 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)
  }

}

Как ни странно, это влияет на производительность прокрутки (по крайней мере, на iOS 12), когда текст переполняет видимый прямоугольник. При вставке 15 он даже перестает прокручиваться.
— Ixx

3

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


3

Абсурдно, что вы должны UITextFieldсоздавать подклассы, поскольку уже реализует методы, как указывает @Adam Waite. Вот быстрое расширение, которое предоставляет фабричный метод, также доступный в репо наших категорий :

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

}

Ссылка в вашем ответе мертва, не могли бы вы обновить ее?
— ВендиКидд

Исправлен URL-адрес @WendiKidd
— Кристофер Пикслей

2

Я поместил 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 / storyboard с пользовательским классом MRDInsetTextField

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

Спасибо. Одно предложение для вашего кода - почему вы использовали CGRect для вставки, а не для UIEdgeInsets?
— ША

2

Это не так коротко, как в других примерах, но использует совершенно другой подход к решению этой проблемы. Обратите внимание, каретка по-прежнему будет начинаться по левому краю, но текст будет правильно вставлен при вводе / отображении. Это работает без подклассов, если вы ищете только левое поле и уже используете 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;
}

Предположение, которое defaultTextAttributesсодержит NSMutableParagraphStyleэто, довольно опасно. Я бы предпочел mutableCopy все это.
— Бен Синклер

1

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

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

Любая причина, почему вы избегаете подклассов? Он является действительным дизайн парадигмы.
— Stunner

1

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

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 Исправлено UITextField

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


1

Вот полный ответ 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

Решение, которое действительно работает и охватывает все случаи:

  • Если использовать offsetByне insetBy.
  • Также следует вызвать супер функцию, чтобы получить оригинал Rect.
  • Границы неисправны. вам нужно сместить исходные X, Y. Границы имеют X, Y в виде нулей.
  • Исходный x, y может быть ненулевым, например, при установке leftView UITextField.

Образец:

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

Если вы хотите изменить отступ 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 );
}

-1

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

extension UITextField {
    @IBInspectable var textInsets: CGPoint {
            get {
                return CGPoint.zero
            }
            set {
                layer.sublayerTransform = CATransform3DMakeTranslation(newValue.x, newValue.y, 0);
            }
        }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.