UITextfield leftView / rightView отступы на iOS7


94

Представления leftView и rightView UITextField на iOS7 действительно близки к границе текстового поля.

Как я могу добавить к этим элементам (горизонтальные) отступы?

Я пытался изменить рамку, но не вышло

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



1
Нет, это спрашивает об отступе изображения, отображаемого как leftView в текстовом поле. Не делать отступы в самом тексте. Попробуйте его код, и вы увидите, что установка leftView для изображения помещает это изображение напротив левого края текстового поля без заполнения. Выглядит некрасиво.
— камень

Ответы:


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. В Интерфейсном Разработчике щелкните текстовое поле, которое вы хотите создать подкласс, и измените атрибут класса на имя этого нового подкласса.


как использовать IBDesignable для этого же?
— Ридди

для последней версии или если вы просматриваете это в 2020 году. посетите: stackoverflow.com/a/55041786/6596443
— AKINNUBI ABIOLA SYLVESTER

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

Я использовал ваш пример для UIButton (вместо UIImageView), а его тип - InfoLight.
— OhadM

Я обнаружил, что «.right» вместо «.center» делает его больше похожим на встроенную панель поиска, такую ​​как в приложении «Контакты». Отличное решение по этому поводу, спасибо за его публикацию.
— Джеймс Туми

Или, если вам нужно быть точным в воссоздании дизайна, поместите изображение в левый угол, а затем увеличьте ширину, чтобы добиться точного заполнения
— Йованьованович

4
Похоже, это больше не работает с iOS 13 и Xcode 11 Beta 7. А вот с iOS 11/12 работает нормально.
— PatrickDotStar 02

49

Самый простой способ - добавить UIView в leftView / righView и добавить ImageView в UIView, настроить источник ImageView внутри UIView в любом месте, где угодно, это сработало для меня как шарм. Требуется всего несколько строк кода

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? "

8

Это работает для меня

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

1
У меня был лучший результат, используя rightView.layer.sublayerTransform = CATransform3DMakeTranslation (-10.0f, 0.0f, 0.0f), но +1 для метода
— Тибо Дэвид

Имейте в виду, что это также сместит кнопку «Очистить» текстового поля вправо, что может вытолкнуть ее за край текстового поля. Если вам не нужна кнопка очистки, это отличный подход, иначе, возможно, нет.
— Том Харрингтон

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».

Примечание. Если вы просто зададите заполнение с автоматическим макетом для текстового поля, ваше приложение не будет запускаться и будет отображать только пустой экран.


4

Вместо того, чтобы манипулировать imageView или изображением, мы можем переопределить метод, предоставленный 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
}}

и таким же образом мы можем переопределить функцию ниже для просмотра слева.

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

}

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.
— камень

Вы можете просто добавить изображение в 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
    }
}

Вы захотите:

  • Подкласс 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) границы для установки нужного прямоугольника

пример

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

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!

Я знаю, что добавление слишком большого количества представлений может сделать этот объект немного тяжелее для загрузки. Но когда меня беспокоили трудности, связанные с другими решениями, я обнаружил, что более склонен к этому методу и более гибок в использовании этого метода. ;)

Надеюсь, этот ответ может быть полезным или полезным, чтобы найти другое решение для кого-то еще.

Ура!


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

выше ответы не работают для меня, это работает.
— Марк Дилан Б. Меркадо,

1

// Устанавливаем вид справа для UITextField, 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

Один трюк: добавьте UIView, содержащий UIImageView, в UITextField как rightView. Этот 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

Самый простой способ - просто изменить текстовое поле на 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

Я понимаю, что это старый пост, и этот ответ немного специфичен для моего варианта использования, но я опубликовал его на случай, если другие ищут аналогичное решение. Я хочу переместить leftView или rightView UITextField, но я не помещаю в них изображения и не хочу никаких жестко закодированных констант.

Мой пользовательский интерфейс требует скрыть кнопку очистки текстового поля и отобразить UIActivityIndicatorView там, где находится кнопка очистки.

Я добавляю счетчик в файл rightView, но из коробки (на iOS 13) он сдвинут на 20 пикселей вправо от clearButton. Я не люблю использовать магические числа, так как положение clearButton и rightView может быть изменено Apple в любое время. Смысл дизайна пользовательского интерфейса - «прядильщик там, где находится кнопка очистки», поэтому я решил создать подкласс UITextField и переопределить rightViewRect(forBounds).

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

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

Ниже приведен рабочий пример (без раскадровки):

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

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

}

//------------------------------------------------------------------------------
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.