使用UITextBorderStyleNone设置UITextField的内边距

418

我想为我的UITextFields使用自定义背景。虽然这样可以工作得很好,但问题是我必须使用UITextBorderStyleNone才能使其看起来漂亮。这将强制文本紧贴左侧且没有填充。

我是否可以手动设置填充,以使其外观类似于UITextBorderStyleRoundedRect,而不使用自定义背景图像?

32个回答

873

我发现了一个聪明的小技巧,可以设置左侧填充的精确大小。

基本上,你需要将 UITextField 的 leftView 属性设置为空视图,并且该视图的大小与你想要设置的填充大小相同:

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textField.leftView = paddingView;
textField.leftViewMode = UITextFieldViewModeAlways;

对我非常有效!

Swift 3 / Swift 4 中,可以通过执行以下操作来完成

let paddingView: UIView = UIView(frame: CGRect(x: 0, y: 0, width: 5, height: 20))
textField.leftView = paddingView
textField.leftViewMode = .always

1
正是我所需要的,只不过我需要向右填充,这基本上是相同的,谢谢! - cg.
1
使用ARC,如果我在多个文本字段中重复使用*paddingView,为什么我的应用程序会挂起并使用大量CPU? - The Muffin Man
3
这个方案不好,最好考虑一下Nate Flink的。这个方案没有编辑模式填充。 - Jacek Kwiecień
3
无法与多个文本框一起使用。会消耗大量内存并最终崩溃。 - birdcage
2
为什么这个代码被接受且有700多个赞?它没有在左边添加填充。举个例子,如果我已经在使用textfield的leftView做了某些事情,那该怎么办? - Zaporozhchenko Oleksandr
显示剩余10条评论

184

我创建了这个类别实现,并将其添加到.m文件的顶部。

@implementation UITextField (custom)
    - (CGRect)textRectForBounds:(CGRect)bounds {
        return CGRectMake(bounds.origin.x + 10, bounds.origin.y + 8,
                          bounds.size.width - 20, bounds.size.height - 16);
    }
    - (CGRect)editingRectForBounds:(CGRect)bounds {
        return [self textRectForBounds:bounds];
    }
@end

根据Piotr Blasiak提供的链接,这种方法似乎比创建一个全新的子类更简单,也比添加额外的UIView更简单。但是,似乎缺少某些东西来控制文本字段内部的填充。

Swift 4解决方案:

class CustomTextField: UITextField {
    struct Constants {
        static let sidePadding: CGFloat = 10
        static let topPadding: CGFloat = 8
    }

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return CGRect(
            x: bounds.origin.x + Constants.sidePadding,
            y: bounds.origin.y + Constants.topPadding,
            width: bounds.size.width - Constants.sidePadding * 2,
            height: bounds.size.height - Constants.topPadding * 2
        )
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return self.textRect(forBounds: bounds)
    }
}

6
这会触发有关类别覆盖方法的警告。请参见此答案以抑制它们。 - pdenya
5
除了不将此操作归类,这个解决方案比被接受的答案更为简洁。 - Bob Vork
2
最好使用CGRectInset()做类似这样的事情,而不是自己编写。 这样看起来更加简洁:return CGRectInset(bounds, 10, 8); - Dennis Munsie
@EgeAkpinar 但是如果我们想在四个方向上使用不同的填充怎么办..?我们可以在这种情况下使用 CGRectInset 吗..? - shashwat
1
@shashwat 是的,你可以指定任何想要的填充。 - Ege Akpinar
1
当我4年前添加这个功能时,iOS的情况是不同的,我同意现在最好创建一个子类。然而,如果你只想快速而简单地检查像素距离,那么这个方法就可以胜任;所以人们继续投票也没关系! - Nate Flink

146

这是适用于Xcode >6的Swift 3版本,您可以在Interface Builder / Storyboard中编辑插入值。

import UIKit

@IBDesignable
class FormTextField: UITextField {

    @IBInspectable var inset: CGFloat = 0

    override func textRect(forBounds bounds: CGRect) -> CGRect {
        return bounds.insetBy(dx: inset, dy: inset)
    }

    override func editingRect(forBounds bounds: CGRect) -> CGRect {
        return textRect(forBounds: bounds)
    }

}

输入图像描述


1
我在我的表单中没有看到文本字段。 - oky_sabeni
2
我需要添加这行代码 override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) } - Michael
2
这个答案如果能够附上@IBDesignable@IBInspectable的解释或者相关链接,会更有帮助。比如这篇文章:http://nshipster.com/ibinspectable-ibdesignable/。 - Russell Austin
2
如果你依赖于任何附属视图(例如UITextField上的清除按钮功能),那么return super.textRectForBounds(CGRectInset(bounds, inset, inset))将正确处理附属视图的偏移量。 - Mike Fay
Swift 3 > 转到“显示身份检查器”添加您的“自定义类”。在此示例中,将“FormTextField”添加到自定义类中。 - Fran Ceriu
显示剩余4条评论

79

编辑:在iOS 11.3.1中仍可使用

在iOS 6中,myTextField.leftView = paddingView;会导致问题。

这解决了问题。

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

如要右对齐文本字段,请按照评论中 latenitecoder 的建议使用 CATransform3DMakeTranslation(-5, 0, 0)


1
不错,我必须在应用程序的所有文本字段中添加填充。我创建了一个UITextField的类别,并将以下代码放入其中-(void)awakeFromNib{},这解决了我的问题。 - Teena nath Paul
1
所有其他评论都假定您想从左侧填充UITextField。子类化是为了添加一些间距而增加了很多开销,我宁愿只添加一些空白字符,但这个解决方案是最好的解决方案。一行代码,未来可靠。如果您正在使用文本右对齐的文本字段,请使用负值(-5,0,0)。谢谢Inder。 - latenitecoder
最近我遇到了一个问题,我的应用在模拟器上看起来很正常,但是在实际设备上文本和占位符都不可见,实际上它们似乎隐藏在屏幕中央(双击粘贴时会显示指针在那里)。 - Chris Edwards
1
4年后,我终于找到了自己的答案:D,@latenitecoder你的评论正是所需之物。正在更新答案。 - Inder Kumar Rathore
1
如果我想要左右两侧的填充,我该怎么做呢? - Mina Gerges
显示剩余3条评论

71

一个好的方法是通过创建子类并添加edgeInsets属性来为UITextField添加填充。然后设置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 = UIEdgeInsetsZero;
    }
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder{
    self = [super initWithCoder:aDecoder];
    if(self){
        self.edgeInsets = UIEdgeInsetsZero;
    }
    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

这应该是被接受的答案。它也适用于右视图和左视图。 - NSPratik

25

只需像这样对UITextField进行子类化:

@implementation DFTextField


- (CGRect)textRectForBounds:(CGRect)bounds
{
    return CGRectInset(bounds, 10.0f, 0);
}

- (CGRect)editingRectForBounds:(CGRect)bounds
{
    return [self textRectForBounds:bounds];
}


@end

这将在每侧添加10点的水平填充。


22
  1. 创建一个名为 Custom 的文本字段

PaddingTextField.swift

import UIKit
class PaddingTextField: UITextField {

@IBInspectable var paddingLeft: CGFloat = 0
@IBInspectable var paddingRight: CGFloat = 0

override func textRectForBounds(bounds: CGRect) -> CGRect {
    return CGRectMake(bounds.origin.x + paddingLeft, bounds.origin.y,
        bounds.size.width - paddingLeft - paddingRight, bounds.size.height);
}

override func editingRectForBounds(bounds: CGRect) -> CGRect {
    return textRectForBounds(bounds)
}}
  1. 将您的文本框类设置为 PaddingTextField 并根据需要自定义填充。enter image description here enter image description here

  2. 享受它!

final


21

Objective C 代码

MyTextField.h

#import <UIKit/UIKit.h>

@interface MyTextField : UITextField

@property (nonatomic) IBInspectable CGFloat padding;

@end

我的TextField.m

#import "MyTextField.h"

IB_DESIGNABLE
@implementation MyTextField

@synthesize padding;

-(CGRect)textRectForBounds:(CGRect)bounds{
    return CGRectInset(bounds, padding, padding);
}

-(CGRect)editingRectForBounds:(CGRect)bounds{
    return [self textRectForBounds:bounds];
}

@end

在此输入图片描述


1
https://developer.apple.com/library/ios/recipes/xcode_help-IB_objects_media/Chapters/CreatingaLiveViewofaCustomObject.html - Henadzi Rabkin
关于 [self textRectForBounds:bounds];,文档明确提到不要直接调用它:https://developer.apple.com/documentation/uikit/uitextfield/1619636-textrect - Pierre

18
根据Evil Trout的回答,您可能希望创建一个类别,以便在多个应用程序中更轻松地使用它。
头文件:
@interface UITextField (PaddingText)

-(void) setLeftPadding:(int) paddingValue;

-(void) setRightPadding:(int) paddingValue;
@end

实现文件:

#import "UITextField+PaddingText.h"

@implementation UITextField (PaddingText)

-(void) setLeftPadding:(int) paddingValue
{
    UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, paddingValue, self.frame.size.height)];
    self.leftView = paddingView;
    self.leftViewMode = UITextFieldViewModeAlways;
}

-(void) setRightPadding:(int) paddingValue
{
    UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, paddingValue, self.frame.size.height)];
    self.rightView = paddingView;
    self.rightViewMode = UITextFieldViewModeAlways;
}

@end

使用示例

#import "UITextField+PaddingText.h"

[self.YourTextField setLeftPadding:20.0f];

希望这能帮到你们

谢谢


16

Swift版本:

extension UITextField {
    @IBInspectable var padding_left: CGFloat {
        get {
            LF.log("WARNING no getter for UITextField.padding_left")
            return 0
        }
        set (f) {
            layer.sublayerTransform = CATransform3DMakeTranslation(f, 0, 0)
        }
    }
}
为了在IB中分配值。

在Interface Builder中表示的IBInspectable设置


IBInspectable 允许您在运行时应用 setter 代码,因此只需将数字放入 Interface Builder 中即可正常工作。 - superarts.org
当您有“清除按钮”时,这种方法将无效。如果使用此解决方案,您的清除按钮将不可见。 - Bhavin_m

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接