【发布时间】:2011-04-13 05:27:35
【问题描述】:
我想为我的UITextFields 使用自定义背景。这很好用,除了我必须使用UITextBorderStyleNone 让它看起来很漂亮。这会强制文本在没有任何填充的情况下粘在左侧。
除了使用我的自定义背景图像外,我可以手动设置填充,使其看起来类似于UITextBorderStyleRoundedRect?
【问题讨论】:
标签: ios uitextfield padding
我想为我的UITextFields 使用自定义背景。这很好用,除了我必须使用UITextBorderStyleNone 让它看起来很漂亮。这会强制文本在没有任何填充的情况下粘在左侧。
除了使用我的自定义背景图像外,我可以手动设置填充,使其看起来类似于UITextBorderStyleRoundedRect?
【问题讨论】:
标签: ios uitextfield padding
我发现了一个巧妙的小技巧来为这种确切的情况设置左侧填充。
基本上,您将 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
【讨论】:
*paddingView,为什么我的应用会挂起并占用大量 CPU?
我创建了这个类别实现并将其添加到.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)
}
}
【讨论】:
适用于 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)
}
}
【讨论】:
override func placeholderRectForBounds(bounds: CGRect) -> CGRect { return CGRectInset(bounds, inset, inset) }
@IBDesignable 和 @IBInspectable 所做的事情会更有帮助,i.e. this post at nshipster
return super.textRectForBounds(CGRectInset(bounds, inset, inset)) 将正确处理与附件视图的偏移量。
编辑:在 iOS 11.3.1 中仍然有效
在 iOS 6 中 myTextField.leftView = paddingView; 导致问题
这样就解决了问题
myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(5, 0, 0)
对于右对齐的文本字段,请使用 CATransform3DMakeTranslation(-5, 0, 0),正如 latenitecoder 在 cmets 中提到的那样
【讨论】:
向 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 = 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
【讨论】:
像这样子类化 UITextField:
@implementation DFTextField
- (CGRect)textRectForBounds:(CGRect)bounds
{
return CGRectInset(bounds, 10.0f, 0);
}
- (CGRect)editingRectForBounds:(CGRect)bounds
{
return [self textRectForBounds:bounds];
}
@end
这会在两侧添加 10 个点的水平填充。
【讨论】:
目标 C 代码
MyTextField.h
#import <UIKit/UIKit.h>
@interface MyTextField : UITextField
@property (nonatomic) IBInspectable CGFloat padding;
@end
MyTextField.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
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)
}}
【讨论】:
根据 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];
希望对大家有所帮助
干杯
【讨论】:
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 中赋值
【讨论】:
IBInspectable 允许您在运行时应用设置器代码,因此只需将您的号码输入Interface Builder 即可。
Clear Button 时,这将不起作用。如果应用此解决方案,您的清除按钮将不可见。
您不能设置填充。取而代之的是UIView,其中包含您的背景图像和其中的UITextField。将UITextField宽度设置为UIViewWidth-(paddingSize x 2),高度设置为paddingSize,paddingSize。
【讨论】:
像这样子类化 UITextField(Swift 版本):
import UIKit
class CustomTextField: UITextField {
override func textRectForBounds(bounds: CGRect) -> CGRect {
return CGRectInset(bounds, 25.0, 0)
}
override func editingRectForBounds(bounds: CGRect) -> CGRect {
return self.textRectForBounds(bounds)
}
}
这会在两侧添加 25.0 个点的水平填充。
【讨论】:
我是基于 Nate 的解决方案,但后来我发现这会在您使用 leftView/rightView 属性时引起问题,因此最好调整 super 的实现,因为它会考虑左/右视图。
- (CGRect)textRectForBounds:(CGRect)bounds {
CGRect ret = [super textRectForBounds:bounds];
ret.origin.x = ret.origin.x + 5;
ret.size.width = ret.size.width - 10;
return ret;
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
【讨论】:
Swift 3 的更新版本:
@IBDesignable
class FormTextField: UITextField {
@IBInspectable var paddingLeft: CGFloat = 0
@IBInspectable var paddingRight: CGFloat = 0
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + paddingLeft, y: bounds.origin.y, width: bounds.size.width - paddingLeft - paddingRight, height: bounds.size.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return textRect(forBounds: bounds)
}
}
【讨论】:
根据@Evil Trout 投票最多的答案,我在我的 ViewController 类中创建了一个自定义方法,如下所示:
- (void) modifyTextField:(UITextField *)textField
{
UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)];
textField.leftView = paddingView;
textField.leftViewMode = UITextFieldViewModeAlways;
textField.rightView = paddingView;
textField.rightViewMode = UITextFieldViewModeAlways;
[textField setBackgroundColor:[UIColor whiteColor]];
[textField setTextColor:[UIColor blackColor]];
}
现在我可以在内部调用该方法(viewDidLoad 方法)并将我的任何 TextFields 发送到该方法并为左右添加填充,并通过仅编写一行代码来提供文本和背景颜色,如下所示:
[self modifyTextField:self.firstNameTxtFld];
这在 iOS 7 上完美运行! 我知道添加太多视图可能会使这个类加载得更重一些。但是当担心其他解决方案的困难时,我发现自己更倾向于这种方法,并且使用这种方式更灵活。 ;)
感谢黑客“邪恶鳟鱼”! (鞠躬)
我想我应该用 Swift 更新这个答案的代码 sn-p:
既然 Swift 允许我们为现有的类编写扩展,我们就这样写吧。
extension UITextField {
func addPaddingToTextField() {
let paddingView: UIView = UIView.init(frame: CGRectMake(0, 0, 8, 20))
self.leftView = paddingView;
self.leftViewMode = .Always;
self.rightView = paddingView;
self.rightViewMode = .Always;
self.backgroundColor = UIColor.whiteColor()
self.textColor = UIColor.blackColor()
}
}
用法:
self.firstNameTxtFld.addPaddingToTextField()
希望这对其他人有帮助!
干杯!
【讨论】:
以下是在 SWIFT 中实现这一目标的方法
@IBOutlet weak var yourTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
let paddingView = UIView(frame: CGRectMake(0, 0, 10, self.yourTextField.frame.height))
yourTextField.leftView = paddingView
yourTextField.leftViewMode = UITextFieldViewMode.Always
}
}
【讨论】:
Swift 2.0 版本:
let paddingView: UIView = UIView(frame: CGRectMake(0, 0, 5, 20))
textField.leftView = paddingView
textField.leftViewMode = UITextFieldViewMode.Always;
【讨论】:
如果有人正在寻找Swift 4.0 版本,那么extension 以下的版本就可以了。它同时具有Left 和Right 填充UITextField。实际上它是IBInspectable 用于情节提要配置。您可以直接从 Interface Builder / Storyboard 设置值。这是在 Swift 4.0 版本和 Xcode 9.0 中测试过的代码
请记住,如果您想在同一个 UITextField 上启用 Clear Button,则必须将 Right Padding 保留为空白。
import UIKit
extension UITextField {
@IBInspectable var paddingLeft: CGFloat {
get {
return leftView!.frame.size.width
}
set {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))
leftView = paddingView
leftViewMode = .always
}
}
@IBInspectable var paddingRight: CGFloat {
get {
return rightView!.frame.size.width
}
set {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height))
rightView = paddingView
rightViewMode = .always
}
}
}
【讨论】:
^ 这些建议非常适合那些以编程方式创建界面的人。
但是对于我们这些使用 Xcode 界面生成器的人来说,有两种 LAZY EASY WAY:
更简单:将 UIImageView 放在文本字段后面
最简单:将您的边框样式更改为简单的黑色正方形(左起第二个选项),然后将您的图像添加为背景图像。图像优先于正方形,因此,您仍然可以获得正常图像背景所需的填充,而不会实际绘制正方形。
编辑:您也可以使用黑色球体(在 IB 中选择 UITextBox 时从左数第三个选项),它不适用于最右边的“图形球体”样式。
【讨论】:
最好的方法是使用 UITextField 的子类和 .m 文件创建一个类
#import "CustomTextField.h"
#import <QuartzCore/QuartzCore.h>
@implementation CustomTextField
- (id)initWithCoder:(NSCoder*)coder
{
self = [super initWithCoder:coder];
if (self) {
//self.clipsToBounds = YES;
//[self setRightViewMode:UITextFieldViewModeUnlessEditing];
self.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0,15,46)];
self.leftViewMode=UITextFieldViewModeAlways;
}
return self;
}
通过这样做转到您的故事板或 xib 并单击身份检查器并将 UITextfield 替换为您自己的“CustomTextField”类选项。
注意:如果您只是为文本字段提供自动布局填充,那么您的应用程序将不会运行并且仅显示空白屏幕。
【讨论】:
Swift 3 版本:
class CustomTextField:UITextField{
required init?(coder aDecoder: NSCoder){
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect.init(x: bounds.origin.x + 8, y: bounds.origin.y, width: bounds.width, height: bounds.height)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return self.textRect(forBounds:bounds)
}
}
【讨论】:
Nate Flink's 答案是我最喜欢的,但不要忘记右/左视图。
例如 UITextField 子类:
override func rightViewRectForBounds(bounds: CGRect) -> CGRect {
let rightViewBounds = super.rightViewRectForBounds(bounds)
return CGRectMake(CGRectGetMinX(rightViewBounds) - 10, CGRectGetMinY(rightViewBounds), CGRectGetWidth(rightViewBounds), CGRectGetHeight(rightViewBounds))
}
以上代码为rightView 的UITextField 设置右填充。
【讨论】:
Swift 3 解决方案
class CustomTextField: UITextField {
override func textRect(forBounds bounds: CGRect) -> CGRect {
return CGRect(x: bounds.origin.x + 10, y: bounds.origin.y + 8, width: bounds.size.width - 20, height: bounds.size.height - 16)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return self.textRect(forBounds: bounds)
}
}
【讨论】:
这是在 UITextfield 中提供填充的 Swift 代码
func txtPaddingVw(txt:UITextField) {
let paddingView = UIView(frame: CGRectMake(0, 0, 10, 10))
txt.leftViewMode = .Always
txt.leftView = paddingView
}
并调用使用
self.txtPaddingVw(txtPin)
【讨论】:
您可以使用类别。设置左右内边距
UITextField+Padding.h
@interface UITextField (Padding)
@property (nonatomic, assign) CGFloat paddingValue;
@property (nonatomic, assign) CGFloat leftPadding;
@property (nonatomic, assign) CGFloat rightPadding;
//overwrite
-(CGRect)textRectForBounds:(CGRect)bounds;
-(CGRect)editingRectForBounds:(CGRect)bounds;
@end
UITextField+Padding.m
#import "UITextField+Padding.h"
#import <objc/runtime.h>
static char TAG_LeftPaddingKey;
static char TAG_RightPaddingKey;
static char TAG_Left_RightPaddingKey;
@implementation UITextField (Padding)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
-(CGRect)textRectForBounds:(CGRect)bounds {
CGFloat offset_Left=0;
CGFloat offset_Right=0;
if (self.paddingValue>0) {
offset_Left=self.paddingValue;
offset_Right=offset_Left;
}else{
if (self.leftPadding>0){
offset_Left=self.leftPadding;
}
if (self.rightPadding>0){
offset_Right=self.rightPadding;
}
}
if (offset_Left>0||offset_Right>0) {
return CGRectMake(bounds.origin.x+ offset_Left ,bounds.origin.y ,
bounds.size.width- (offset_Left+offset_Right), bounds.size.height-2 );
}else{
return bounds;
}
}
-(CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
#pragma clang diagnostic pop
#pragma maek -setter&&getter
- (CGFloat)paddingValue
{
return [objc_getAssociatedObject(self,&TAG_Left_RightPaddingKey) floatValue];
}
-(void)setPaddingValue:(CGFloat)paddingValue
{
objc_setAssociatedObject(self, &TAG_Left_RightPaddingKey, @(paddingValue), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(CGFloat)leftPadding
{
return [objc_getAssociatedObject(self,&TAG_LeftPaddingKey) floatValue];
}
-(void)setLeftPadding:(CGFloat)leftPadding
{
objc_setAssociatedObject(self, &TAG_LeftPaddingKey, @(leftPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(CGFloat)rightPadding
{
return [objc_getAssociatedObject(self,&TAG_RightPaddingKey) floatValue];
}
-(void)setRightPadding:(CGFloat)rightPadding
{
objc_setAssociatedObject(self, &TAG_RightPaddingKey, @(rightPadding), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
你可以这样设置内边距 self.phoneNumTF.paddingValue=10.f; 要么 self.phoneNumTF.leftPadding=10.f;
【讨论】:
@Evil trout 的回答很棒。我已经使用这种方法很长一段时间了。它唯一缺少的是“处理大量文本字段”。我尝试了其他方法,但似乎不起作用。
子类化 UITextField 只是为了添加一个填充对我来说没有任何意义。因此,我遍历了所有 UITextFields 以添加填充。
-(void) addPaddingToAllTextFields:(UIView*)view {
for(id currentView in [view subviews]){
if([currentView isKindOfClass:[UITextField class]]) {
// Change value of CGRectMake to fit ur need
[currentView setLeftView:[[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 20)]];
[currentView setLeftViewMode:UITextFieldViewModeAlways];
}
if([currentView respondsToSelector:@selector(subviews)]){
[textfieldarray addObjectsFromArray:[self addPaddingToAllTextFields:currentView]];
}
}
}
【讨论】:
textfieldarray 没有在第二个if 块中定义,我在用for(id subSubView in [view subviews]){[self addPaddingToAllTextFields:subSubView];} 替换第二个if 的内容后成功使用了这个sn-p(谢谢!)
Brody 的解决方案非常适合我。我不得不在文本字段上添加侧视图并添加额外的填充。因此,通过将自定义 UIEdgeInsets 属性实现到 UITextField 子类,我设法完成了任务。我将在我的所有项目中使用这个新的子类。
【讨论】:
到目前为止,我发现的最佳解决方案是类别。这就是我向左右添加 5 点填充的方式:
@implementation UITextField (Padding)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
- (CGRect)textRectForBounds:(CGRect)bounds {
return CGRectMake(bounds.origin.x + 5, bounds.origin.y,
bounds.size.width - 10, bounds.size.height);
}
- (CGRect)editingRectForBounds:(CGRect)bounds {
return [self textRectForBounds:bounds];
}
#pragma clang diagnostic pop
@end
#pragma 只是为了消除烦人的警告
【讨论】:
textField.layer.borderWidth = 3;
将添加边框,这对我来说是填充。
【讨论】:
另一个考虑因素是,如果您有多个 UITextField 来添加填充,请为每个文本字段创建一个单独的 UIView - 因为它们不能共享。
【讨论】: