Відповіді:
Переопределення -textRectForBounds:
змінить лише вставку тексту-заповнювача. Щоб змінити вставку тексту, який можна редагувати, вам також потрібно переозначити-editingRectForBounds:
// placeholder position
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectInset(bounds, 10, 10);
}
// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
return CGRectInset(bounds, 10, 10);
}
UITextField
вона знаходиться в межах UIScrollView
.
- (CGRect)clearButtonRectForBounds:(CGRect)bounds { return CGRectMake(x, y, w, h); }
Знайдено тут: stackoverflow.com/questions/5361369/…
Я зміг це зробити через:
myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);
Звичайно, пам’ятайте, що імпортувати QuartzCore, а також додати Framework до свого проекту.
UITextField
перекриває вміст праворуч від нього.
Якщо вам потрібен лише лівий запас, ви можете спробувати це:
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;
Це працює для мене. Я сподіваюся, що це може допомогти.
leftView.backgroundColor = textField.backgroundColor;
... Окрім цього чудового рішення ... Спасибі (:
У класі, отриманому з UITextField, замініть принаймні ці два методи:
- (CGRect)textRectForBounds:(CGRect)bounds;
- (CGRect)editingRectForBounds:(CGRect)bounds;
Це може бути таким же простим, якщо у вас немає додаткового вмісту:
return CGRectInset(bounds , 10, 10);
UITextField надає кілька методів позиціонування, які ви можете перекрити.
- (CGRect)borderRectForBounds:(CGRect)bounds; - (CGRect)placeholderRectForBounds:(CGRect)bounds; - (CGRect)clearButtonRectForBounds:(CGRect)bounds; - (CGRect)leftViewRectForBounds:(CGRect)bounds; - (CGRect)rightViewRectForBounds:(CGRect)bounds;
Як щодо @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)
}
}
let rect = CGRect(x: bounds.minX, y: bounds.minY + insetY, width: bounds.width, height: bounds.height) return CGRectInset(rect , insetX , 0)
textRect
/ в editingRect
) впливає на продуктивність прокрутки (принаймні на iOS 12), коли текст переповнює видиму пряму. З вставкою 15 він навіть перестає прокручуватися.
Якщо у вас є чітка кнопка, прийнята відповідь не буде працювати для вас. Ми також повинні вберегтись від того, щоб 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+ працювали на мене.
clearButtonRectForBounds:
просто допомагає трохи натиснути кнопку очищення зліва. Можливо, ви хочете залишити це. Моє текстове поле було на темному тлі, і кнопка очищення потребувала трохи додаткової накладки праворуч.
Думав, що я поставлю швидке рішення
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)
}
}
override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
textRectForBounds
, це також впливає на заповнення заповнювача, тож додавання заповнення заповнення вводить вставку ще на 10 пунктів. Якщо це те, що ви шукаєте, 👍🏼, але якщо ні, то це добре знати.
Використання textRectForBounds:
- це правильний підхід. Я зафіксував це у своєму підкласі, щоб ви могли просто використовувати textEdgeInsets
. Див. SSTextField .
Швидкий
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)
}
}
Для людей, які шукають більш легкого рішення.
Додайте UITextField
всередину a UIView
. Для імітації вставки навколо текстового поля я тримаю 10 пікс ліворуч, а ширина на 20 пікселів менша, ніж перегляд. Для округлої кутової межі навколо текстового поля використовуйте рамку подання
viewBG.layer.cornerRadius = 8.0;
viewBG.layer.borderColor = [UIColor darkGrayColor].CGColor;
viewBG.layer.borderWidth = 1.0;
UITextView
можливо?
Ви можете встановити вставку тексту для 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;
imageView.contentMode = UIViewContentMode.Center imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 16.0, imageView.image!.size.height)
Швидкий
// adjust place holder text
let paddingView = UIView(frame: CGRectMake(0, 0, 10, usernameOrEmailField.frame.height))
usernameOrEmailField.leftView = paddingView
usernameOrEmailField.leftViewMode = UITextFieldViewMode.Always
Хороший підхід для додавання прокладок до 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
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)
}
}
використання:
&
Це найшвидший спосіб, який я знайшов, не роблячи жодних підкласів:
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
Ось той самий підклас 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)
}
Версія 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)
}
}
Ви можете налаштувати позиціонування тексту в текстовому полі, зробивши його підкласом UITextField
та замінивши -textRectForBounds:
метод.
Абсурдно, що вам належить підклас, оскільки вони UITextField
вже реалізують методи, як вказує @Adam Waite. Ось швидке розширення, яке відкриває заводський метод, також доступне в наших категоріях repo :
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)
}
}
Я підкласив 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
Це не так коротко, як інші приклади, але вимагає зовсім іншого підходу до вирішення цієї проблеми. Зауважте, карета все ще почне переходити на лівий край, але текст буде належним чином з відступом при введенні / відображенні. Це працює без підкласифікації, якщо ви шукаєте лише лівий край і ви вже використовуєте 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
є досить небезпечним. Я б скоріше змінявкопіювати все це.
Я зазвичай намагаюся уникати підкласифікації, але це працює, якщо ви вже:
// 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)];
}
Щоб включити інше рішення, яке не потребує підкласифікації:
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];
Тестовано з iOS 7 та iOS 8. Обидва працюють. Тим не менш, може виникнути шанс Apple змінити ієрархію шарів UITextField, що погано викручує речі.
Ось вичерпна відповідь 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)
}
}
Рішення, яке фактично працює і охоплює всі випадки:
offsetBy
не insetBy
.Rect
.Зразок:
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)
}
Якщо ви хочете лише змінити відступ 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 );
}
Швидке рішення без підкласу та також перевіряється
extension UITextField {
@IBInspectable var textInsets: CGPoint {
get {
return CGPoint.zero
}
set {
layer.sublayerTransform = CATransform3DMakeTranslation(newValue.x, newValue.y, 0);
}
}
}