UITextfield leftView / rightView dopełnienie w systemie iOS7

94

Widoki leftView i rightView UITextField na iOS7 są naprawdę blisko granicy pola tekstowego.

Jak mogę dodać (poziome) wypełnienie do tych elementów?

Próbowałem zmodyfikować ramkę, ale nie zadziałało

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

Proszę zauważyć, że nie jestem zainteresowany dodawaniem dopełnienia do tekstu pola tekstowego, jak to Ustaw dopełnienie dla UITextField z UITextBorderStyleNone

poniżej zera
źródło
możliwy duplikat wstawki tekstowej dla UITextField?
Zorayr
1
Nie, to pytanie o wcięcie obrazu wyświetlanego jako leftView w polu tekstowym. Bez wcięcia samego tekstu. Wypróbuj jego kod, a zobaczysz, że ustawienie leftView na obrazie umieszcza ten obraz obok lewej krawędzi pola tekstowego, bez dopełnienia. Wygląda brzydko.
kamień

Odpowiedzi:

90

Właśnie nad tym pracowałem i korzystałem z tego rozwiązania:

- (CGRect) rightViewRectForBounds:(CGRect)bounds {

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

Spowoduje to przesunięcie obrazu z prawej strony o 10 zamiast ściśnięcia obrazu przy krawędzi w systemie iOS 7.

Dodatkowo było to w podklasie UITextField, którą można utworzyć za pomocą:

  1. Utwórz nowy plik, który jest podklasą UITextFieldzamiast domyślnejNSObject
  2. Dodaj nową metodę o nazwie, - (id)initWithCoder:(NSCoder*)coderaby ustawić obraz

    - (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. Być może będziesz musiał zaimportować #import <QuartzCore/QuartzCore.h>

  4. Dodaj rightViewRectForBoundspowyższą metodę

  5. W programie Interface Builder kliknij pole tekstowe, które chcesz utworzyć podklasę, i zmień atrybut klasy na nazwę nowej podklasy

AngeloS
źródło
jak używać IBDesignable do tego samego?
riddhi
dla najnowszej wersji lub jeśli przeglądasz to w 2020 roku. odwiedź: stackoverflow.com/a/55041786/6596443
AKINNUBI ABIOLA SYLVESTER
167

Znacznie prostsze rozwiązanie, które wykorzystuje 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;

W 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
Wsi
źródło
1
Możesz także użyć ScaleAspectFit zamiast środka ... jeśli rozmiar obrazu nie pasuje do dokładnej klatki.
Mihir Mehta
Użyłem twojego przykładu dla UIButton (zamiast UIImageView), podczas gdy jego typ to InfoLight.
OhadM,
Zauważyłem, że „.right” zamiast „.center” bardziej przypomina wbudowany pasek wyszukiwania, taki jak w aplikacji Kontakty. Świetne rozwiązanie w tej sprawie, dzięki za opublikowanie.
James Toomey
Lub jeśli chcesz być precyzyjny w odtwarzaniu projektu, umieść obraz po lewej stronie, a następnie zwiększ szerokość, aby uzyskać dokładne wypełnienie
jovanjovanovic
4
Wygląda na to, że nie działa już z iOS 13 i Xcode 11 Beta 7. Działa jednak dobrze na iOS 11/12.
PatrickDotStar
49

Najłatwiej jest dodać UIView do leftView / righView i dodać ImageView do UIView, dostosować pochodzenie ImageView wewnątrz UIView, gdziekolwiek chcesz, to działało dla mnie jak urok. Potrzebuje tylko kilku wierszy kodu

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];
vishal dharankar
źródło
UIViewContentMode nie działa, ale ta odpowiedź działa jak urok!
nigong
14

Działa to świetnie w 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
Andrzej
źródło
nie można przekonwertować wartości typu „string” na oczekiwany typ argumentu „UIImage?”
8

To działa dla mnie

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

Niech ci to pomoże.

Ashu
źródło
6

Podoba mi się to rozwiązanie, ponieważ rozwiązuje problem za pomocą jednej linii kodu

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

Uwaga: .. lub 2, jeśli rozważasz włączenie linii QuartzCore :)

Jordi Corominas
źródło
1
To również przesuwa granicę
Softlion,
1
ale nie rozwiązuje problemu z prawą wyściółką tylko lewy problem z wyściółką
carmen_munich
1
Lepszy wynik uzyskałem używając rightView.layer.sublayerTransform = CATransform3DMakeTranslation (-10.0f, 0.0f, 0.0f), ale +1 dla metody
Thibaud David
Pamiętaj, że spowoduje to również przesunięcie przycisku „Wyczyść” pola tekstowego w prawo, co może spowodować przesunięcie go poza krawędź pola tekstowego. Jeśli nie potrzebujesz wyraźnego przycisku, jest to świetne podejście, w przeciwnym razie może nie.
Tom Harrington,
4

Najlepszym sposobem na to jest po prostu utworzenie klasy przy użyciu podklasy UITextField w pliku .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;

}

robiąc to, przejdź do swojego storyboardu lub xib i kliknij inspektora tożsamości i zastąp pole UITextfield własną opcją „CustomTextField” w klasie.

Uwaga: Jeśli po prostu podasz dopełnienie z automatycznym układem dla pola tekstowego, Twoja aplikacja nie będzie działać i pokaże tylko pusty ekran.

Anuj Kumar Rai
źródło
4

Zamiast manipulować imageView lub image, możemy zastąpić metodę dostarczoną przez Apple dla 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
}}

w ten sam sposób możemy nadpisać poniższą funkcję dla widoku z lewej strony.

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

}
Pranav Gupta
źródło
3

Znalazłem to gdzieś ...

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

[self addSubview:itemDescription];
Wyrażenie regularne
źródło
4
To po prostu dodaje dopełnienie do tekstu, co nie jest tym, czego szuka pytający. Nie chce wyraźnego widoku z lewej strony. Chce, aby obraz był wyświetlany jako lewy widok.
kamień
Możesz po prostu dodać obraz w paddingView.
Matheus Weber
3

Szybki 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ędziesz chciał:

  • Podklasa UITextField
  • Wpisz unieważnioną metodę w polu tekstowym z podklasą
  • W unieważnionej metodzie utwórz UIView większy niż twój obraz
  • Umieść swój obraz w widoku
  • Przypisz widok do UITextField.rightView
bkSwifty
źródło
2

Oto jedno rozwiązanie:

 UIView *paddingTxtfieldView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 42)]; // what ever you want 
 txtfield.leftView = paddingTxtfieldView;
 txtfield.leftViewMode = UITextFieldViewModeAlways;
Dev Patel
źródło
1

Utwórz niestandardową klasę UITextField i użyj tej klasy zamiast UITextField. Zastąp - (CGRect) textRectForBounds: (CGRect) bounds, aby ustawić prostą, której potrzebujesz

Przykład

- (CGRect)textRectForBounds:(CGRect)bounds{
     CGRect textRect = [super textRectForBounds:bounds];
     textRect.origin.x += 10;
     textRect.size.width -= 10;
     return textRect;
}
Kedar
źródło
1

Poniższy przykład dotyczy dodawania poziomego dopełnienia do widoku z lewej strony, który jest ikoną - możesz użyć podobnego podejścia do dodawania dopełnienia do dowolnego UIView, którego chcesz użyć jako lewego widoku pola tekstowego.

UITextFieldPodklasa wewnętrzna :

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

Chociaż jesteśmy UITextFieldtutaj podklasą , uważam, że jest to najczystsze podejście.

Zorayr
źródło
1
- (CGRect)rightViewRectForBounds:(CGRect)bounds
{
    return CGRectMake(bounds.size.width - 40, 0, 40, bounds.size.height);
}
carmen_munich
źródło
Jeśli UITextFieldjest osadzony w a UISearchBar, jak powiedzieć, UISearchBaraby używał twojej UITextFieldpodklasy?
crishoj
1

dziękuję wam za odpowiedzi, ku mojemu zdziwieniu żadna z nich tak naprawdę nie pasowała do mojego pola tekstowego we właściwym widoku, jednocześnie zapewniając wymagane wypełnienie. potem pomyślałem o użyciu trybu AspectFill i zdarzyły się cuda. dla przyszłych poszukiwaczy, oto czego użyłem:

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 w ramce mojego imageview reprezentuje wysokość mojego emailTextfield, nie krępuj się dostosować go do swoich potrzeb.

carlos16196
źródło
1

Sam miałem ten problem i zdecydowanie najłatwiejszym rozwiązaniem jest zmodyfikowanie obrazu, aby po prostu dodać dopełnienie z każdej strony obrazu!

Właśnie zmieniłem mój obraz png, aby dodać 10-pikselowe przezroczyste wypełnienie i działa dobrze, bez żadnego kodowania!

Richard
źródło
1

Jeśli używasz UIImageView jako leftView, musisz użyć tego kodu:

Uwaga: nie używaj inside viewWillAppear ani 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;
}
Zeeshan
źródło
1

Utworzyłem niestandardową metodę w mojej klasie ViewController, jak pokazano poniżej:

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

Teraz mogę wywołać tę metodę wewnątrz ( viewDidLoadmetoda) i wysłać dowolną z moich TextFieldsdo tej metody i dodać dopełnienie dla prawej i lewej strony oraz nadać tekstowi i kolorom tła, pisząc tylko jedną linię kodu w następujący sposób:

[self modifyTextField:self.firstNameTxtFld];

To działało idealnie na iOS 7! Mam nadzieję, że to nadal działa również na iOS 8 i 9!

Wiem, że dodanie zbyt dużej liczby widoków może spowodować, że ładowanie tego obiektu będzie nieco cięższe. Ale kiedy martwiłem się o trudności w innych rozwiązaniach, stwierdziłem, że jestem bardziej skłonny do tej metody i bardziej elastyczny w używaniu jej. ;)

Mam nadzieję, że ta odpowiedź może być pomocna lub przydatna w znalezieniu innego rozwiązania dla kogoś innego.

Twoje zdrowie!

Randika Vishman
źródło
1

To działa dla mnie tak, jak szukam:

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
}
Aleksandr Skorotkin
źródło
1

Od iOS 13 i Xcode 11 jest to jedyne rozwiązanie, które działa dla nas.

// 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
    }
}
PatrickDotStar
źródło
powyższe odpowiedzi nie działają dla mnie, ten działa.
Mark Dylan B Mercado
1

// Ustaw widok z prawej strony 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

NSurajit
źródło
0

Jedna sztuczka: Dodaj UIView zawierający UIImageView do UITextField jako rightView. Ten UIView musi być większy, teraz umieść UIImageView po lewej stronie. Więc będzie dopełnienie przestrzeni od prawej strony.

// 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;
Suraj Mirajkar
źródło
0

Najłatwiej jest po prostu zmienić pole tekstowe na RoundRect zamiast na niestandardowe i zobaczyć magię. :)

Shilpa
źródło
0

dla Swift2 używam

...
        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
...
Haiyuan
źródło
0
...
textField.rightView = UIImageView(image: ...)
textField.rightView?.contentMode = .top
textField.rightView?.bounds.size.height += 10
textField.rightViewMode = .always
...
Rafael Sachetto
źródło
0

Proste podejście:

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

Uwaga: wysokość powinna być mniejsza niż szerokość, aby umożliwić dopełnienie w poziomie.

Mukesh Shakya
źródło
0

Zdaję sobie sprawę, że to stary post i ta odpowiedź jest nieco specyficzna dla mojego przypadku użycia, ale opublikowałem ją na wypadek, gdyby inni szukali podobnego rozwiązania. Chcę przenieść leftView lub rightView UITextField, ale nie umieszczam w nich obrazów i nie chcę żadnych stałych zakodowanych na stałe.

Mój interfejs użytkownika wymaga ukrycia przycisku czyszczenia pola tekstowego i wyświetlenia UIActivityIndicatorView, w którym znajduje się przycisk czyszczenia.

Dodaję spinner do rightView, ale po wyjęciu z pudełka (na iOS 13) jest on przesunięty o 20 pikseli w prawo od clearButton. Nie lubię używać magicznych liczb, ponieważ pozycja clearButton i rightView może ulec zmianie w dowolnym momencie przez Apple. Założeniem projektu interfejsu użytkownika jest „spinner, w którym znajduje się przycisk czyszczenia”, więc moim rozwiązaniem było utworzenie podklasy UITextField i zastąpienie rightViewRect(forBounds).

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

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

Poniżej znajduje się działający przykład (bez 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()
    }

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

}

//------------------------------------------------------------------------------
Swany
źródło