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.