iOS7上UITextfield左/右视图填充问题

95

iOS7 下的 UITextField 的 leftView 和 rightView 紧贴着边框,如何添加一些(水平)内边距呢?我试过修改 frame,但没有用。

uint padding = 10;//padding for iOS7
UIImageView * iconImageView = [[UIImageView alloc] initWithImage:iconImage];    
iconImageView.frame = CGRectMake(0 + padding, 0, 16, 16);
textField.leftView = iconImageView;
请注意,我对在文本字段的文本中添加填充不感兴趣,例如这样的做法:设置UITextField的填充和UITextBorderStyleNone

可能是 UITextField 的文本缩进? 的重复问题。 - Zorayr
1
不,这是在询问如何缩进作为文本字段中leftView显示的图像,而不是缩进文本本身。尝试使用他的代码,你会发现将leftView设置为图像会将该图像放置在文本字段的左边缘,没有填充。它看起来很丑。 - stone
28个回答

167

一种更简单的解决方案,利用了contentMode

    arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"down_arrow"]];
    arrow.frame = CGRectMake(0.0, 0.0, arrow.image.size.width+10.0, arrow.image.size.height);
    arrow.contentMode = UIViewContentModeCenter;

    textField.rightView = arrow;
    textField.rightViewMode = UITextFieldViewModeAlways;

在 Swift 3 中,

    let arrow = UIImageView(image: UIImage(named: "arrowDrop"))
    if let size = arrow.image?.size {
        arrow.frame = CGRect(x: 0.0, y: 0.0, width: size.width + 10.0, height: size.height)
    }
    arrow.contentMode = UIViewContentMode.center
    self.textField.rightView = arrow
    self.textField.rightViewMode = UITextFieldViewMode.always

1
如果图像的大小与确切的框架不匹配,您也可以使用ScaleAspectFit而不是中心。 - Mihir Mehta
我在使用你的 UIButton 示例(而不是 UIImageView),其类型为 InfoLight。 - OhadM
我发现使用“.right”而不是“.center”更像内置搜索栏,例如联系人应用程序中的搜索栏。这是一个很好的解决方案,感谢您发布它。 - James Toomey
8
在 iOS 13 和 Xcode 11 Beta 7 上似乎不再起作用了,但在 iOS 11/12 上表现良好。 - PatrickDotStar
@primoz 我已将我的解决方案添加为答案 https://dev59.com/N2Ik5IYBdhLWcg3wU82o#60721059 - PatrickDotStar
显示剩余2条评论

101

我刚刚自己处理了这个问题,使用了这个解决方案:

- (CGRect) rightViewRectForBounds:(CGRect)bounds {

    CGRect textRect = [super rightViewRectForBounds:bounds];
    textRect.origin.x -= 10;
    return textRect;
}

这将把图片从右边移动10个单位,而不是在iOS 7中将图片挤压到边缘。

此外,这是UITextField的子类,可以通过以下方式创建:

  1. 创建一个新文件,它是UITextField的子类,而不是默认的NSObject
  2. 添加一个名为- (id)initWithCoder:(NSCoder*)coder的新方法来设置图片

    - (id)initWithCoder:(NSCoder*)coder {
        self = [super initWithCoder:coder];
    
        if (self) {
    
            self.clipsToBounds = YES;
            [self setRightViewMode:UITextFieldViewModeUnlessEditing];
    
            self.leftView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"textfield_edit_icon.png"]];
        }
    
        return self;
    }
    
  3. 你可能需要导入#import <QuartzCore/QuartzCore.h>

  4. 在上面添加rightViewRectForBounds方法

  5. 在Interface Builder中,单击您想要子类化的TextField并将类属性更改为这个新子类的名称


如何使用IBDesignable实现同样的效果? - riddhi
如果您正在查看此内容的最新版本或者是在2020年之后,请访问以下链接:https://dev59.com/N2Ik5IYBdhLWcg3wU82o#55041786 - AKINNUBI ABIOLA SYLVESTER

51

最简单的方法是将UIView添加到leftView/righView中,并将ImageView添加到UIView中,在UIView内随意调整ImageView的原点位置,这对我非常有效。只需要几行代码

UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 5, 26, 26)];
imgView.image = [UIImage imageNamed:@"img.png"];

UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
[paddingView addSubview:imgView];
[txtField setLeftViewMode:UITextFieldViewModeAlways];
[txtField setLeftView:paddingView];

UIViewContentMode 不起作用,但这个答案非常有效! - nigong

15

这对 Swift 来说很棒:

let imageView = UIImageView(image: UIImage(named: "image.png"))
imageView.contentMode = UIViewContentMode.Center
imageView.frame = CGRectMake(0.0, 0.0, imageView.image!.size.width + 20.0, imageView.image!.size.height)
textField.rightViewMode = UITextFieldViewMode.Always
textField.rightView = imageView

无法将类型为"string"的值转换为预期的参数类型"UIImage?"。 - user4203956

9

这对我有用

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

希望能对你有所帮助。


6

我喜欢这个解决方案,因为它只需要一行代码就能解决问题。

myTextField.layer.sublayerTransform = CATransform3DMakeTranslation(10.0f, 0.0f, 0.0f);

注意:如果您考虑包含QuartzCore,则为1行,否则为2行 :)

1
这也会移动边框。 - Softlion
1
但是它并没有解决右填充的问题,仅解决了左填充的问题。 - Carmen
1
我使用 rightView.layer.sublayerTransform = CATransform3DMakeTranslation(-10.0f, 0.0f, 0.0f) 取得了更好的结果,但是对该方法还是要点赞。 - Thibaud David
请注意,这也会将文本字段的“清除”按钮向右移动,这可能会将其推到文本字段的边缘之外。如果您不需要清除按钮,则这是一个很好的方法,否则可能不太适合。 - Tom Harrington

6

Swift 5

class CustomTextField: UITextField {
    func invalidate() {
        let errorImage =  UIImageView(image: UIImage(named: "errorImage"))
        errorImage.frame = CGRect(x: 8, y: 8, width: 16, height: 16)
        rightView = UIView(frame: CGRect(x: 0, y: 0, width: 32, height: 32))
        rightView?.addSubview(errorImage)
        rightViewMode = .always
    }
}

您需要:
  • 继承UITextField
  • 在继承的文本字段中编写一个invalidate方法
  • 在invalidate方法中,创建一个大于您的图像的UIView
  • 将您的图像放置在该视图中
  • 将视图分配给UITextField.rightView

5

我们可以覆盖苹果提供的rightView方法,而不是操纵imageView或图像。

class CustomTextField : UITextField { 

override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
    let offset = 5
    let width  = 20
    let height = width
    let x = Int(bounds.width) - width - offset
    let y = offset
    let rightViewBounds = CGRect(x: x, y: y, width: width, height: height)
    return rightViewBounds
}}

同样的方式,我们可以重写以下函数以获取左侧视图。

override func leftViewRect(forBounds bounds: CGRect) -> CGRect {
    /*return as per requirement*/

}

4
最好的方法是使用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;

}

通过这种方式,您需要前往Storyboard或XIB并单击“Identity Inspector”,然后在类选项中将UITextfield替换为您自己的“CustomTextField”。

注意:如果您仅使用自动布局对文本字段进行填充,则应用程序将无法运行,并且只显示空白屏幕。


4

自从iOS 13和Xcode 11发布以来,这是我们唯一可行的解决方案。

// Init of custom UITextField
override init(frame: CGRect) {
    super.init(frame: frame)

    if let size = myButton.imageView?.image?.size {
        myButton.frame = CGRect(x:0, y: 0, width: size.width, height: size.height)

        let padding: CGFloat = 5
        let container = UIView(frame: CGRect(x:0, y: 0, width: size.width + padding, height: size.height))
        container.addSubview(myButton)

        myButton.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            myButton.topAnchor.constraint(equalTo: container.topAnchor),
            myButton.leftAnchor.constraint(equalTo: container.leftAnchor),
            myButton.bottomAnchor.constraint(equalTo: container.bottomAnchor),
            myButton.rightAnchor.constraint(equalTo: container.rightAnchor, constant: -padding),
        ])

        textField.rightViewMode = .always
        textField.rightView = container
    }
}

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