UITextfield leftView / rightView padding trên iOS7


94

Chế độ xem leftView và rightView của UITextField trên iOS7 thực sự gần với đường viền trường văn bản.

Làm cách nào để thêm một số đệm (ngang) vào các mục đó?

Tôi đã thử sửa đổi khung hình, nhưng không hoạt động

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

Xin lưu ý rằng tôi không quan tâm đến việc thêm đệm vào văn bản của trường văn bản, như thế này Đặt đệm cho UITextField với UITextBorderStyleNone


bản sao có thể có của nội dung văn bản cho UITextField?
Zorayr

1
Không, đây là câu hỏi về cách thụt lề hình ảnh được hiển thị dưới dạng Chế độ xem bên trái trong trường văn bản. Không tự thụt lề văn bản. Hãy thử mã của anh ấy và bạn sẽ thấy rằng cài đặt leftView thành một hình ảnh sẽ đặt hình ảnh lên cạnh trái của trường văn bản, không có phần đệm. Nó trông thật xấu xí.
stone

Câu trả lời:


90

Tôi chỉ đang làm việc trên này và sử dụng giải pháp này:

- (CGRect) rightViewRectForBounds:(CGRect)bounds {

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

Thao tác này sẽ di chuyển hình ảnh từ bên phải sang 10 thay vì hình ảnh bị ép lên so với cạnh trong iOS 7.

Ngoài ra, nó nằm trong một lớp con của UITextField, có thể được tạo bởi:

  1. Tạo tệp mới là lớp con UITextFieldthay vì lớp mặc địnhNSObject
  2. Thêm một phương thức mới có tên - (id)initWithCoder:(NSCoder*)coderđể đặt hình ảnh

    - (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. Bạn có thể phải nhập #import <QuartzCore/QuartzCore.h>

  4. Thêm rightViewRectForBoundsphương thức ở trên

  5. Trong Trình tạo giao diện, nhấp vào Trường văn bản mà bạn muốn tạo lớp con và thay đổi thuộc tính lớp thành tên của lớp con mới này


làm thế nào để sử dụng IBDesignable cho cái này?
riddhi,

cho phiên bản mới nhất hoặc nếu bạn đang xem nội dung này vào năm 2020. hãy truy cập: stackoverflow.com/a/55041786/6596443
AKINNUBI ABIOLA SYLVESTER

167

Một giải pháp đơn giản hơn nhiều, tận dụng lợi thế của 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;

Trong 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
Bạn cũng có thể sử dụng ScaleAspectFit thay vì center ... nếu kích thước của hình ảnh không khớp với khung chính xác.
Mihir Mehta

Tôi đã sử dụng ví dụ của bạn cho UIButton (thay vì UIImageView) trong khi loại của nó là InfoLight.
OhadM

Tôi nhận thấy rằng ".right" thay vì ".center" khiến thanh này trông giống thanh Tìm kiếm tích hợp sẵn hơn, chẳng hạn như thanh trong ứng dụng Danh bạ. Giải pháp tuyệt vời về điều này, cảm ơn vì đã đăng nó.
James Toomey

Hoặc nếu bạn cần để được chính xác trong giải trí thiết kế, đưa hình ảnh vào .left và sau đó tăng chiều rộng để đạt được chính xác đệm
jovanjovanovic

4
Điều này dường như không hoạt động nữa với iOS 13 và Xcode 11 Beta 7. Tuy nhiên, hoạt động tốt trên iOS 11/12.
PatrickDotStar

49

Cách dễ nhất là thêm UIView vào leftView / righView và thêm ImageView vào UIView, điều chỉnh nguồn gốc của ImageView bên trong UIView ở bất kỳ đâu bạn thích, điều này đối với tôi như một sự quyến rũ. Nó chỉ cần vài dòng mã

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 không có tác dụng nhưng câu trả lời này hoạt động như một sự quyến rũ!
nigong

14

Điều này hoạt động tốt cho 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

không thể chuyển đổi giá trị của loại 'chuỗi' để dự đoán kiểu lập luận 'UIImage "?

7

Điều này phù hợp với tôi

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

Có thể nó sẽ giúp bạn.


6

Tôi thích giải pháp này vì nó giải quyết được vấn đề chỉ với một dòng mã

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

Lưu ý: .. hoặc 2 nếu bạn cân nhắc bao gồm QuartzCore một dòng :)


1
Điều này cũng di chuyển biên giới
Softlion

1
nhưng không giải quyết được vấn đề với đệm đúng chỉ vấn đề padding trái
carmen_munich

1
Tôi đã có kết quả tốt hơn khi sử dụng rightView.layer.sublayerTransform = CATransform3DMakeTranslation (-10.0f, 0.0f, 0.0f), nhưng +1 cho phương pháp này
Thibaud David

Hãy nhớ rằng điều này cũng sẽ chuyển nút "xóa" của trường văn bản sang bên phải, nút này có thể đẩy nó qua mép của trường văn bản. Nếu bạn không cần nút xóa, đây là một cách tiếp cận tuyệt vời, nếu không có thể không.
Tom Harrington

4

Cách tốt nhất để làm điều này đơn giản là tạo một lớp bằng cách sử dụng lớp con của UITextField và trong tệp .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;

}

bằng cách thực hiện việc này, hãy truy cập bảng phân cảnh hoặc xib của bạn và nhấp vào trình kiểm tra danh tính và thay thế UITextfield bằng "CustomTextField" của riêng bạn trong tùy chọn lớp.

Lưu ý: Nếu bạn chỉ cung cấp đệm với bố cục tự động cho trường văn bản thì ứng dụng của bạn sẽ không chạy và chỉ hiển thị màn hình trống.


4

Thay vì mô tả imageView hoặc image, chúng ta có thể ghi đè một phương thức do apple cung cấp cho 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
}}

và theo cách tương tự, chúng ta có thể ghi đè bên dưới func cho chế độ xem bên trái.

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

}

3

Tôi tìm thấy cái này ở đâu đó ...

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

[self addSubview:itemDescription];

4
Điều đó chỉ thêm phần đệm vào văn bản, đây không phải là thứ mà người hỏi đang tìm kiếm. Anh ấy không muốn có một bên trái rõ ràng. Anh ấy muốn một hình ảnh được hiển thị dưới dạng leftView.
stone

Bạn chỉ có thể thêm hình ảnh vào paddingView.
Matheus Weber

3

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

Bạn sẽ muốn:

  • Lớp con UITextField
  • Viết một phương thức vô hiệu hóa bên trong trường văn bản lớp con
  • Trong phương pháp vô hiệu hóa, hãy tạo một UIView hình ảnh lớn hơn hình ảnh của bạn
  • Đặt hình ảnh của bạn bên trong chế độ xem
  • Gán chế độ xem cho UITextField.rightView

2

Đây là một giải pháp:

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

1

Tạo một lớp UITextField tùy chỉnh và sử dụng lớp đó thay vì UITextField. Ghi đè - (CGRect) textRectForBounds: (CGRect) giới hạn để đặt trực tràng mà bạn cần

Thí dụ

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

1

Ví dụ dưới đây là để thêm phần đệm ngang vào dạng xem bên trái mà tình cờ là một biểu tượng - bạn có thể sử dụng cách tiếp cận tương tự để thêm phần đệm vào bất kỳ UIViewcái nào bạn muốn sử dụng làm chế độ xem bên trái của trường văn bản.

Lớp UITextFieldcon bên trong :

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

Mặc dù chúng tôi là một phân lớp UITextFieldở đây, nhưng tôi tin rằng đây là cách tiếp cận sạch sẽ nhất.


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

Nếu cái UITextFieldđược nhúng trong a UISearchBar, làm cách nào để bạn bảo cái UISearchBarsử dụng UITextFieldlớp con của bạn ?
khủng hoảng

1

cảm ơn các bạn vì câu trả lời của mình, tôi ngạc nhiên là không ai trong số họ thực sự phù hợp với hình ảnh xem đúng với trường văn bản của tôi trong khi vẫn cung cấp phần đệm cần thiết. sau đó tôi nghĩ đến việc sử dụng chế độ AspectFill và điều kỳ diệu đã xảy ra. cho những người tìm kiếm trong tương lai, đây là những gì tôi đã sử dụng:

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;

35 trong khung của lần xem hình ảnh của tôi đại diện cho chiều cao của trường emailText của tôi, vui lòng điều chỉnh nó theo nhu cầu của bạn.


1

Bản thân tôi đã gặp sự cố này và cho đến nay giải pháp đơn giản nhất là sửa đổi hình ảnh của bạn để chỉ cần thêm phần đệm vào mỗi bên của hình ảnh!

Tôi vừa thay đổi hình ảnh png của mình để thêm phần đệm trong suốt 10 pixel, và nó hoạt động tốt mà không cần mã hóa gì cả!


1

Nếu bạn đang sử dụng UIImageView dưới dạng leftView thì bạn phải sử dụng mã này:

Thận trọng: Không sử dụng bên trong viewWillAppear hoặc 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

Tôi đã tạo một phương thức tùy chỉnh trong lớp ViewController của mình, như được hiển thị bên dưới:

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

Bây giờ tôi có thể gọi phương thức đó bên trong ( viewDidLoadphương thức) và gửi bất kỳ phương thức nào của tôi TextFieldstới phương thức đó và thêm phần đệm cho cả bên phải và bên trái, đồng thời cung cấp cho văn bản và màu nền bằng cách viết chỉ một dòng mã, như sau:

[self modifyTextField:self.firstNameTxtFld];

Điều này hoạt động hoàn hảo trên iOS 7! Hy vọng tính năng này vẫn hoạt động trên iOS 8 và 9!

Tôi biết rằng việc thêm quá nhiều Chế độ xem có thể làm cho đối tượng này nặng hơn một chút để được tải. Nhưng khi lo ngại về khó khăn trong các giải pháp khác, tôi thấy mình thiên về phương pháp này hơn và linh hoạt hơn khi sử dụng cách này. ;)

Hy vọng câu trả lời này có thể hữu ích hoặc hữu ích để tìm ra giải pháp khác cho người khác.

Chúc mừng!


1

Điều này phù hợp với tôi giống như tôi đang tìm kiếm:

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

Kể từ iOS 13 và Xcode 11, đây là giải pháp duy nhất phù hợp với chúng tôi.

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

Câu trả lời trên không hoạt động đối với tôi, câu trả lời này hoạt động.
Mark Dylan B Mercado

1

// Đặt Chế độ xem bên phải của UITextField, nhanh chóng 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

Một mẹo nhỏ: Thêm một UIView chứa UIImageView vào UITextField dưới dạng rightView. UIView này phải có kích thước lớn hơn, bây giờ hãy đặt UIImageView ở bên trái của nó. Vì vậy, sẽ có một khoảng đệm từ bên phải.

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

Cách dễ nhất là chỉ cần thay đổi Textfield thành RoundRect thay vì Custom và xem điều kỳ diệu. :)


0

cho Swift2, tôi sử dụng

...
        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.rightView = UIImageView(image: ...)
textField.rightView?.contentMode = .top
textField.rightView?.bounds.size.height += 10
textField.rightViewMode = .always
...

0

Cách tiếp cận đơn giản:

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

Lưu ý: Chiều cao nên nhỏ hơn chiều rộng để đệm ngang.


0

Tôi nhận ra đây là một bài đăng cũ và câu trả lời này hơi cụ thể đối với trường hợp sử dụng của tôi, nhưng tôi đã đăng nó trong trường hợp những người khác đang tìm kiếm một giải pháp tương tự. Tôi muốn di chuyển leftView hoặc rightView của UITextField nhưng tôi không đưa hình ảnh vào chúng và không muốn bất kỳ hằng số được mã hóa cứng nào.

Giao diện người dùng của tôi yêu cầu ẩn nút xóa của trường văn bản và hiển thị UIActivityIndicatorView nơi đặt nút xóa.

Tôi thêm một con quay vào rightView, nhưng ra khỏi hộp (trên iOS 13), nó bị dịch chuyển 20 pixel sang bên phải clearButton. Tôi không thích sử dụng các con số kỳ diệu vì vị trí của clearButton và rightView có thể thay đổi bất kỳ lúc nào bởi Apple. Mục đích thiết kế giao diện người dùng là "spinner ở nơi có nút rõ ràng" vì vậy giải pháp của tôi là phân lớp UITextField và ghi đè rightViewRect(forBounds).

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

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

Dưới đây là một ví dụ làm việc (sans 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()
    }

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

}

//------------------------------------------------------------------------------
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.