UITextfield iOS7上的leftView / rightView填充


93

iOS7上的UITextField的leftView和rightView视图实际上靠近文本框边框。

如何在这些项目中添加一些(水平)填充?

我尝试修改框架,但是没有用

uint padding = 10;//padding for iOS7
UIImageView * iconImageView = [[UIImageView alloc] initWithImage:iconImage];    
iconImageView.frame = CGRectMake(0 + padding, 0, 16, 16);
textField.leftView = iconImageView;

请注意,我对在文本字段的文本中添加填充不感兴趣,例如使用UITextBorderStyleNone设置UITextField的填充



1
不,这是关于缩进显示为文本字段中leftView的图像的问题。不缩进文本本身。尝试他的代码,您将看到将leftView设置为图像会将图像靠在文本字段的左边缘,而不会填充。看起来很丑。
2015年

Answers:


90

我自己只是在做这个工作,并使用了以下解决方案:

- (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,然后将class属性更改为该新子类的名称。


如何为此使用IBDesignable?
riddhi

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而不是center...。
Mihir Mehta 2015年

我将示例用于UIButton(而不是UIImageView),而其类型是InfoLight。
OhadM '16

我发现“ .right”而不是“ .center”使它看起来更像内置的搜索栏,例如“联系人”应用程序中的搜索栏。很好的解决方案,谢谢张贴。
James Toomey

或者,如果您需要在设计娱乐方面保持精确,请将图像放到.left位置,然后增加宽度以实现精确的填充
jovanjovanovic

4
但是,这似乎不适用于iOS 13和Xcode 11 Beta 7。
PatrickDotStar

49

最简单的方法是将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

14

这对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?”

7

这对我有用

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);

注意:..或2,如果您考虑将QuartzCore包括在内:)


1
这也会移动边界
Softlion

1
但不能用右填充来解决问题,而只能用左填充问题解决
carmen_munich 2015年

1
使用rightView.layer.sublayerTransform = CATransform3DMakeTranslation(-10.0f,0.0f,0.0f),我得到了更好的结果,但是该方法+1
Thibaud David

请记住,这还将使文本字段的“清除”按钮向右移动,这会将其推过文本字段的边缘。如果您不需要清除按钮,这是一个很好的方法,否则可能不需要。
汤姆·哈灵顿

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;

}

通过执行此操作,转到您的情节提要或xib,然后单击“身份检查器”,并在类选项中将UITextfield替换为您自己的“ CustomTextField”。

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


3

我在某个地方发现了这个...

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

[self addSubview:itemDescription];

4
这只会在文本中添加填充,这不是问询者所要的。他不需要清晰的leftView。他希望将图像显示为leftView。
石头

您可以只在paddingView中添加图像。
Matheus Weber

3

代替操纵imageView或image,我们可以重写apple为rightView提供的方法。

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
}}

同样,我们可以在func下面覆盖左视图。

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

}

3

迅捷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方法中,创建一个UIView 比您的图片大的图片
  • 将图片放在视图中
  • 将视图分配给 UITextField.rightView

2

这是一种解决方案:

 UIView *paddingTxtfieldView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 42)]; // what ever you want 
 txtfield.leftView = paddingTxtfieldView;
 txtfield.leftViewMode = UITextFieldViewModeAlways;

1

创建一个自定义UITextField类,并使用该类代替UITextField。覆盖-(CGRect)textRectForBounds:(CGRect)bounds设置所需的矩形

- (CGRect)textRectForBounds:(CGRect)bounds{
     CGRect textRect = [super textRectForBounds:bounds];
     textRect.origin.x += 10;
     textRect.size.width -= 10;
     return textRect;
}

1

下面的示例用于向恰好是图标的左视图中添加水平填充-您可以使用类似的方法UIView向要用作文本字段的左视图的任何内容中添加填充。

内部UITextField子类:

static CGFloat const kLeftViewHorizontalPadding = 10.0f;

@implementation TextFieldWithLeftIcon
{
  UIImage *_image;
  UIImageView *_imageView;
}

- (instancetype)initWithFrame:(CGRect)frame image:(UIImage *)image
{
  self = [super initWithFrame:frame];
  if (self) {
    if (image) {
      _image = image;
      _imageView = [[UIImageView alloc] initWithImage:image];
      _imageView.contentMode = UIViewContentModeCenter;
      self.leftViewMode = UITextFieldViewModeAlways;
      self.leftView = _imageView;
    }
  }
  return self;
}

#pragma mark - Layout 

- (CGRect)leftViewRectForBounds:(CGRect)bounds
{
  CGFloat widthWithPadding = _image.size.width + kLeftViewHorizontalPadding * 2.0f;
  return CGRectMake(0, 0, widthWithPadding, CGRectGetHeight(bounds));
}

尽管我们在UITextField这里是子类,但我认为这是最干净的方法。


1
- (CGRect)rightViewRectForBounds:(CGRect)bounds
{
    return CGRectMake(bounds.size.width - 40, 0, 40, bounds.size.height);
}

如果UITextField嵌入在中UISearchBar,如何告诉子类UISearchBar使用UITextField
crishoj

1

谢谢你们的回答,令我惊讶的是,他们都没有在我的文本字段中正确显示正确的视图图像,同时仍然提供了所需的填充。然后我想到使用AspectFill模式,奇迹发生了。对于将来的求职者,这是我使用的方式:

UIImageView *emailRightView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 35, 35)];
emailRightView.contentMode = UIViewContentModeScaleAspectFill;
emailRightView.image = [UIImage imageNamed:@"icon_email.png"];
emailTextfield.rightViewMode = UITextFieldViewModeAlways;
emailTextfield.rightView = emailRightView;

我的imageview框架中的35代表我的emailTextfield的高度,可以根据需要进行调整。


1

我自己遇到了这个问题,到目前为止,最简单的解决方案是修改您的图像,以简单地在图像的每一侧添加填充!

我只是更改了png图像以添加10像素的透明填充,并且效果很好,根本没有编码!


1

如果您将UIImageView用作leftView,则必须使用以下代码:

注意:请勿在viewWillAppear或viewDidAppear内部使用

-(UIView*)paddingViewWithImage:(UIImageView*)imageView andPadding:(float)padding
{
    float height = CGRectGetHeight(imageView.frame);
    float width =  CGRectGetWidth(imageView.frame) + padding;

    UIView *paddingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];

    [paddingView addSubview:imageView];

    return paddingView;
}

1

我在ViewController类中创建了一个自定义方法,如下所示:

- (void) modifyTextField:(UITextField *)textField
{
    // Prepare the imageView with the required image
    uint padding = 10;//padding for iOS7
    UIImageView * iconImageView = [[UIImageView alloc] initWithImage:iconImage];    
    iconImageView.frame = CGRectMake(0 + padding, 0, 16, 16);

    // Set the imageView to the left of the given text field.
    textField.leftView = iconImageView;
    textField.leftViewMode = UITextFieldViewModeAlways;
}

现在,我可以在(viewDidLoadmethod)内调用该方法,并将我的任何方法发送TextFields到该方法,并为左右添加填充,并通过仅编写一行代码来给文本和背景色,如下所示:

[self modifyTextField:self.firstNameTxtFld];

这在iOS 7上完美运行!希望这也可以在iOS 8和9上使用!

我知道添加过多的View可能会使此对象的加载重一些。但是,当担心其他解决方案中的困难时,我发现自己更偏向于这种方法,并且使用这种方式更加灵活。;)

希望这个答案可能对寻找其他人的解决方案有所帮助或有用。

干杯!


1

这对我有用,就像我在寻找:

func addImageViewInsideMyTextField() {
    let someView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 24))
    let imageView = UIImageView(image: UIImage(named: "accountImage"))
    imageView.frame = CGRect(x: 16, y: 0, width: 24, height: 24)
    imageView.contentMode = .scaleAspectFit
    someView.addSubview(imageView)

    self.myTextField.leftView = someView
    self.myTextField.leftViewMode = .always
}

1

从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
    }
}

上面的答案对我不起作用,这一个有效。
Mark Dylan B Mercado

1

//设置UITextField的Rightview,Swift 4.2TxtPass.rightViewMode = UITextField.ViewMode.always let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 18, height: 18)) imageView.contentMode = UIView.ContentMode.scaleAspectFit let image = UIImage(named: "hidepass") imageView.image = image let rightView = UIView(frame: CGRect(x: 0, y: 0, width: 28, height: 18)) rightView.addSubview(imageView) rightView.contentMode = UIView.ContentMode.left TxtPass.rightView = rightView


0

一个技巧:将包含UIImageView的UIView作为rightView添加到UITextField。此UIView必须更大,现在将UIImageView放在其左侧。因此,从右开始会有空白。

// Add a UIImageView to UIView and now this UIView to UITextField - txtFieldDate
UIView *viewRightIntxtFieldDate = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 30)]; 
// (Height of UITextField is 30px so height of viewRightIntxtFieldDate = 30px)
UIImageView *imgViewCalendar = [[UIImageView alloc] initWithFrame:CGRectMake(0, 10, 10, 10)];
[imgViewCalendar setImage:[UIImage imageNamed:@"calendar_icon.png"]];
[viewRightIntxtFieldDate addSubview:imgViewCalendar];
txtFieldDate.rightViewMode = UITextFieldViewModeAlways;
txtFieldDate.rightView = viewRightIntxtFieldDate;

0

最简单的方法是将Textfield更改为RoundRect而不是Custom并查看魔术。:)


0

对于Swift2,我使用

...
        self.mSearchTextField.leftViewMode = UITextFieldViewMode.Always
        let searchImg = UIImageView(image: UIImage(named: "search.png"))
        let size = self.mSearchTextField.frame.height
        searchImg.frame = CGRectMake(0, 0, size,size)
        searchImg.contentMode = UIViewContentMode.ScaleAspectFit
        self.mSearchTextField.leftView = searchImg
...


0

简单方法:

textField.rightViewMode = .always
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 25, height: 15))
textField.contentMode = .scaleAspectFit
imageView = UIImage(named: "imageName")
textField.rightView = imageView

注意:高度应小于宽度,以允许水平填充。


0

我意识到这是一篇过时的文章,并且这个答案有点针对我的用例,但是我发布了它,以防其他人寻求类似的解决方案。我想移动UITextField的leftView或rightView,但我不想在其中放置图像,也不需要任何硬编码的常量。

我的UI要求隐藏文本字段的清除按钮,并显示清除按钮所在的UIActivityIndi​​catorView。

我向中添加了一个微调器rightView,但开箱即用(在iOS 13上)将其向右移了20像素clearButton。我不喜欢使用幻数,因为clearButton和rightView的位置随时可能被Apple更改。UI设计的意图是“清除按钮在哪里旋转”,所以我的解决方案是将UITextField子类化并重写rightViewRect(forBounds)

override func rightViewRect(forBounds bounds: CGRect) -> CGRect {

    // Use clearButton's rectangle
    return self.clearButtonRect(forBounds: bounds)
}

以下是一个有效的示例(没有Storyboard):

//------------------------------------------------------------------------------
class myCustomTextField: UITextField {

    override func rightViewRect(forBounds bounds: CGRect) -> CGRect {

        // Use clearButton rectangle
        return self.clearButtonRect(forBounds: bounds)
    }
}

//------------------------------------------------------------------------------
class myViewController: UIViewController {

    var activityView: UIActivityIndicatorView = {
        let activity = UIActivityIndicatorView()
        activity.startAnimating()
        return activity
    }()

    @IBOutlet weak var searchTextField: myCustomTextField!

    //------------------------------------------------------------------------------
    // MARK: - Lifecycle
    //------------------------------------------------------------------------------
    override func viewDidLoad() {

        super.viewDidLoad()

        searchTextField.rightView = activityView
        searchTextField.rightViewMode = .never // Hide spinner
        searchTextField.clearButtonMode = .never // Hide clear button

        setupUIForTextEntry()
    }

    // ...
    // More code to switch between user text entry and "search progress" 
    // by calling setupUI... functions below
    // ...

    //------------------------------------------------------------------------------
    // MARK: - UI
    //------------------------------------------------------------------------------
    func setupUIForTextEntry() {

        // Hide spinner
        searchTextField.rightViewMode = .never

        // Show clear button
        searchTextField.clearButtonMode = .whileEditing
        searchTextField.becomeFirstResponder()
    }

    //------------------------------------------------------------------------------
    func setupUIForSearching() {

        // Show spinner
        searchTextField.rightViewMode = .always

        // Hide clear button
        searchTextField.clearButtonMode = .never
        searchTextField.resignFirstResponder()
    }

    //------------------------------------------------------------------------------

}

//------------------------------------------------------------------------------
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.