我想插入UITextField
的文字。
这可能吗?
答案 0 :(得分:596)
覆盖-textRectForBounds:
只会更改占位符文本的插入内容。要更改可编辑文本的插入内容,您还需要覆盖-editingRectForBounds:
// placeholder position
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectInset(bounds, 10, 10);
}
// text position
- (CGRect)editingRectForBounds:(CGRect)bounds {
return CGRectInset(bounds, 10, 10);
}
答案 1 :(得分:287)
我能够通过以下方式完成:
myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0);
当然记得要导入QuartzCore并将Framework添加到你的项目中。
答案 2 :(得分:165)
在从UITextField派生的类中,至少覆盖以下两种方法:
- (CGRect)textRectForBounds:(CGRect)bounds;
- (CGRect)editingRectForBounds:(CGRect)bounds;
如果您没有其他内容,可能就像这样简单:
return CGRectInset(bounds , 10, 10);
UITextField提供了几种可以覆盖的定位方法。
答案 3 :(得分:158)
如果您只需要左边距,可以试试这个:
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;
它对我有用。我希望这可能有所帮助。
答案 4 :(得分:88)
@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)
}
}
答案 5 :(得分:27)
如果您有一个清除按钮,则接受的答案对您不起作用。我们还应该通过致电super
来防止Apple改变事物。
因此,为了确保文本不与清除按钮重叠,让我们首先从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按以下顺序获取参数: top , left , bottom , right 。
答案 6 :(得分:17)
以为我会提供一个Swift解决方案
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)
}
}
答案 7 :(得分:14)
使用textRectForBounds:
是正确的方法。我已将其包含在我的子类中,因此您只需使用textEdgeInsets
即可。请参阅SSTextField。
答案 8 :(得分:12)
对于那些正在寻找更简单解决方案的人。
在UITextField
内添加UIView
。为了模拟文本字段周围的插图,我保持10 px左边,宽度比视图小20 px。对于文本字段周围的圆角边框,请使用视图的边框
viewBG.layer.cornerRadius = 8.0;
viewBG.layer.borderColor = [UIColor darkGrayColor].CGColor;
viewBG.layer.borderWidth = 1.0;
答案 9 :(得分:12)
您可以通过设置leftView为UITextField设置文本插入。
像这样:
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;
答案 10 :(得分: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
答案 11 :(得分:9)
Swift
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)
}
}
答案 12 :(得分:6)
Swift 3 /可在界面构建器中设计/单独水平&amp;垂直昆虫/开箱即用
@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)
}
}
用法:
&安培;
答案 13 :(得分: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
答案 14 :(得分:4)
这是与Swift 3编写的相同的子类UITextField。它与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)
}
答案 15 :(得分:3)
荒谬的是你必须继承,因为UITextField
已经实现了这些方法,正如@Adam Waite指出的那样。这是一个快速扩展,它公开了一种工厂方法,也可以在categories 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)
}
}
答案 16 :(得分:3)
您可以在文本字段中调整文本的位置,方法是将其作为UITextField
的子类并覆盖-textRectForBounds:
方法。
答案 17 :(得分: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;
}
答案 18 :(得分:2)
我发现roberto.buratti发布的选项是最快的解决方案,它在Swift中:
let leftView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: textField.frame.size.height))
leftView.backgroundColor = textField.backgroundColor
textField.leftView = leftView
textField.leftViewMode = UITextField.ViewMode.always
答案 19 :(得分:2)
答案 20 :(得分: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
答案 21 :(得分:2)
Swift 5版本的Christopher's answer(带有额外的用法示例)
import UIKit
private class InsetTextField: UITextField {
var insets: UIEdgeInsets
init(insets: UIEdgeInsets) {
self.insets = insets
super.init(frame: .zero)
}
required init(coder aDecoder: NSCoder) {
fatalError("not intended for use from a NIB")
}
// placeholder position
override func textRect(forBounds bounds: CGRect) -> CGRect {
return super.textRect(forBounds: bounds.inset(by: insets))
}
// text position
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return super.editingRect(forBounds: bounds.inset(by: insets))
}
}
extension UITextField {
class func textFieldWithInsets(insets: UIEdgeInsets) -> UITextField {
return InsetTextField(insets: insets)
}
}
用法:-
class ViewController: UIViewController {
private let passwordTextField: UITextField = {
let textField = UITextField.textFieldWithInsets(insets: UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15))
// ---
return textField
}()
}
答案 22 :(得分:1)
一种切实可行的解决方案,涵盖所有情况:
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)
}
答案 23 :(得分: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];
使用iOS 7和iOS 8进行测试。 Apple可能仍有机会修改UITextField的层次结构,从而严重搞乱事情。
答案 24 :(得分:1)
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)
}
}
答案 25 :(得分: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)
}
}
答案 26 :(得分: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)];
}
答案 27 :(得分:0)
没有子类的快速解决方案&amp;也可以检查
extension UITextField {
@IBInspectable var textInsets: CGPoint {
get {
return CGPoint.zero
}
set {
layer.sublayerTransform = CATransform3DMakeTranslation(newValue.x, newValue.y, 0);
}
}
}
答案 28 :(得分: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 );
}
答案 29 :(得分:0)
您可能需要这个还支持 leftView 和 rightView 的解决方案。 ?
class InsettedTextField: UITextField {
private let textInset: UIEdgeInsets
var rightViewInset: CGRect {
rightView.flatMap { $0.frame } ?? .zero
}
var leftViewInset: CGRect {
leftView.flatMap { $0.frame } ?? .zero
}
/// Init the text field with insets.
init(textInset: UIEdgeInsets) {
self.textInset = textInset
super.init(frame: .zero)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
bounds
.inset(by: textInset)
.inset(by: UIEdgeInsets(top: 0, left: leftViewInset.width, bottom: 0, right: rightViewInset.width))
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
bounds
.inset(by: textInset)
.inset(by: UIEdgeInsets(top: 0, left: leftViewInset.width, bottom: 0, right: rightViewInset.width))
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
bounds
.inset(by: textInset)
.inset(by: UIEdgeInsets(top: 0, left: leftViewInset.width, bottom: 0, right: rightViewInset.width))
}
}