Текстовая вставка для 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);
}
azdev
источник
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 в ваш проект.

chuthan20
источник
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;

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

roberto.buratti
источник
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 предоставляет несколько методов позиционирования, которые вы можете переопределить.

drawnonward
источник
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)
    }
}
smitt04
источник
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)
    }
}
LCL
источник
Как ни странно, это влияет на производительность прокрутки (по крайней мере, на 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;
Karim
источник
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
LondonGuy
источник
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)
}
}

Применение:

Применение

&

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

zgorawski
источник
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
Firula
источник
Спасибо. Одно предложение для вашего кода - почему вы использовали 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;
}
user3878720
источник
Предположение, которое 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, что испортит ситуацию.

TheGrumpyCoda
источник
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)
}

}
rmooney
источник
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)
}
Hasan
источник
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);
            }
        }
}
Бхавеш Тивари
источник