web-dev-qa-db-fra.com

Comment augmenter la largeur du champ de texte en fonction du texte saisi?

Je dois augmenter la largeur d'un champ de texte en fonction de son contenu. Lorsque l'utilisateur saisit du texte, la taille du champ de texte doit augmenter automatiquement. J'ai un bouton proche (X) à côté de ce champ de texte.

J'ai contraint le champ de texte et le bouton de sorte que le champ de texte soit centré sur l'écran et que le bouton lui soit adjacent. (Le champ de texte doit être modifiable, le bouton doit être cliquable)

La taille du champ de texte est la suivante:

 enter image description here

Lorsque je saisis du texte, la taille devrait automatiquement augmenter:

 enter image description here

Comment puis-je atteindre cet objectif?

21
Mitesh jadav

Je résous mon problème: utilisez ceci pour que textfield ne sort pas de l'écran.

 func getWidth(text: String) -> CGFloat
{
    let txtField = UITextField(frame: .zero)
    txtField.text = text
    txtField.sizeToFit()
    return txtField.frame.size.width
}

func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
{
    let width = getWidth(textField.text!)
    if UIScreen.mainScreen().bounds.width - 55 > width
    {
        txtWidthOfName.constant = 0.0
        if width > txtWidthOfName.constant
        {
            txtWidthOfName.constant = width
        }
        self.view.layoutIfNeeded()
    }
    return true
}

Version Objective C

-(CGFloat)getWidth:(NSString *)text{
    UITextField * textField = [[UITextField alloc]initWithFrame:CGRectZero];
    textField.text = text;
    [textField sizeToFit];
    return textField.frame.size.width;
}

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (self.textFieldName.isEditing == YES) {
        CGFloat width = [self getWidth:textField.text];
        if ([UIScreen mainScreen].bounds.size.width - 60 > width) {
            self.txtWidthOfName.constant = 0.0;
            if (width > self.txtWidthOfName.constant) {
                self.txtWidthOfName.constant = width;
            }
            [self.view layoutIfNeeded];
        }
    }
    return YES;
}
11
Mitesh jadav

Vous pouvez y parvenir en surchargeant la classe UITextField et en renvoyant une valeur personnalisée dans intrinsicContentSize. Vous devez également vous abonner à un événement de changement de texte et invalider la taille du contenu intrinsèque lorsque le changement de texte est animé.

Voici un exemple dans Swift 3

class Test: UITextField {

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupTextChangeNotification()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupTextChangeNotification()
    }

    func setupTextChangeNotification() {
        NotificationCenter.default.addObserver(
            forName: Notification.Name.UITextFieldTextDidChange,
            object: self,
            queue: nil) { (notification) in
                UIView.animate(withDuration: 0.05, animations: {
                    self.invalidateIntrinsicContentSize()
                })
        }
    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    override var intrinsicContentSize: CGSize {
        if isEditing {
            if let text = text,
                !text.isEmpty {
                // Convert to NSString to use size(attributes:)
                let string = text as NSString
                // Calculate size for current text
                var size = string.size(attributes: typingAttributes)
                // Add margin to calculated size
                size.width += 10
                return size
            } else {
                // You can return some custom size in case of empty string
                return super.intrinsicContentSize
            }
        } else {
            return super.intrinsicContentSize
        }
    }
}
11
Vitaliy Gozhenko

Une solution de contournement effrontée pour obtenir la largeur d’une chaîne particulière serait: 

func getWidth(text: String) -> CGFloat {
    let txtField = UITextField(frame: .zero)
    txtField.text = text
    txtField.sizeToFit()
    return txtField.frame.size.width
}

Et pour avoir la largeur,

let width = getWidth(text: "Hello world")
txtField.frame.size.width = width
self.view.layoutIfNeeded() // if you use Auto layout

Si vous avez une contrainte liée à la largeur de txtField, alors faites

yourTxtFieldWidthConstraint.constant = width
self.view.layoutIfNeeded() // if you use Auto layout

Edit Nous créons un UITextField avec un cadre de pratiquement tous les zéros. Lorsque vous appelez sizeToFit (), il définit le cadre de UITextField de manière à afficher tout son contenu sans littéralement plus d'espace. Nous voulions seulement sa largeur, j'ai donc renvoyé la largeur du nouveau UITextField. ARC se chargera de le supprimer de la mémoire pour nous. 

Mettre à jour

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        if textField.text != nil {
            let text = textField.text! as NSString
            let finalString = text.replacingCharacters(in: range, with: string)
            textField.frame.size.width = getWidth(text: finalString)
        }

        return true
    }
7
Matt

Les réponses nécessitent toutes un tas de code, mais vous pouvez tout faire constructeur d’interface; pas de code nécessaire.

Il suffit d’incorporer le textField dans un UIStackView et de contraindre le stackView à être inférieur ou égal à son superview moins une constante (si vous voulez, vous pouvez également lui donner une largeur minimale). StackView veillera à ce que textField conserve toujours sa taille intrinsèque, ou la largeur maximale de stackView (quelle que soit sa taille), de sorte que la taille change automatiquement pour s'adapter au contenu.

3
Josh Homann

Je pense que c'est une meilleure solution que d'avoir une contrainte de largeur que vous devez modifier:

Redimensionne un UITextField lors de la frappe (en utilisant Autolayout)

- (IBAction) textFieldDidChange: (UITextField*) textField
{
    [UIView animateWithDuration:0.1 animations:^{
        [textField invalidateIntrinsicContentSize];
    }];
}

Vous pouvez omettre l'animation si vous le souhaitez.

EDIT: voici un exemple de projet: https://github.com/TomSwift/growingTextField

3
TomSwift

Implémentez la méthode suivante de UITextFieldDelegate. Utilisez l'approche fournie par Matt pour obtenir la largeur requise de textField. Dans la disposition automatique, assurez-vous que les contraintes de centre et de largeur sont définies pour textfield. Créez IBOutlet pour votre contrainte de largeur dans un fichier de code. Assurez-vous également que vous définissez la propriété delegate de votre textField.

@IBOutlet weak var widthConstraint: NSLayoutConstraint!

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
     let width = getWidth(text : textField.text)
     if width > widthConstraint.constant {
         widthConstraint.constant = width
     }
     self.layoutIfNeeded() 
     return true
}
3
Vishnu gondlekar

Nous pouvons facilement le faire en définissant des contraintes UITextField comme ceci:

 enter image description here

// Testé sur Xcode 9.1, Swift 4

Sortie:

 enter image description here

2
jpulikkottil

Cela semble tellement frustrant qu’il n’existe aucun moyen direct, comme il existe un "réducteur automatique" ou une "taille de police minimale" pour UILabel dans IB lui-même ... ". Le réglage de la taille dans IB pour un champ de texte n’est pas bon non plus.

Pourquoi Apple nous oblige-t-il à écrire tout ce code standard, alors qu'un champ de texte nécessite autant que possible la fusion automatique, sinon plus, que le UILabel!

0
iCode