web-dev-qa-db-fra.com

Impossible pour UITextField de réduire automatiquement le texte

J'ai une UITextField dans une cellule de la vue tableau et lorsque le texte devient trop long, j'aimerais que la taille de la police diminue. Je tiens à préciser très clairement que je parle d'une UITextField, pas d'une UILabel ou d'une UITextView. La raison pour laquelle je dis cela est parce que j'ai vu cette question surgir plusieurs fois et les réponses étaient toutes basées sur UILabel au lieu de UITextField. Par exemple, quelqu'un a demandé "Je ne peux pas transférer ma UITextField à la réduction automatique" et la réponse était "assurez-vous que numberOfLines est défini sur 1". À ma connaissance, un UITextField ne possède même pas cette propriété et constitue un contrôle à une seule ligne.

J'ai essayé:

  • dans IB définissant la police sur le système 14.0, minFontSize à 7 et cochant la case "ajuster pour s'adapter"
  • dans le code dans tableView:cellForRowAtIndexPath:
ptCell.name.font = [UIFont systemFontOfSize: 14.0];
ptCell.name.adjustsFontSizeToFitWidth = YES;
ptCell.name.minimumFontSize = 7.0;

mais ni l'un ni l'autre n'ont fonctionné. J'entends par là qu'au lieu de réduire le texte, il tronque la queue.

Est-ce que quelqu'un sait ce que je manque? Cela devrait probablement fonctionner parce que j'ai vu d'autres questions se plaindre que l'utilisateur le fait quand l'utilisateur ne le souhaite pas.

19
hvanbrug

J'ai utilisé la réponse publiée par @Purva comme point de départ pour trouver cette méthode qui donne la taille de police requise, en commençant par la taille de police configurée, et en ne dépassant pas la taille de police minimale configurée. Alors que @Purva a testé la hauteur du texte, il fallait que la largeur s’ajuste. Cette méthode peut être placée dans une catégorie ou une sous-classe de UITextField. Je l'ai dans une sous-classe qui capture également la UITextFieldTextDidChangeNotification. Depuis ce gestionnaire de notification, j'appelle la nouvelle méthode et redimensionne la police si nécessaire. Je l'appelle aussi lorsque j'attribue un nouveau texte au champ de texte pour m'assurer qu'il conviendra au sous-classement - (void)setText: (NSString*)text.

Dans chaque cas, lorsque j'appelle, j'utilise le code suivant:

    CGFloat requiredFontSize = self.requiredFontSize;
    if( self.font.pointSize != requiredFontSize )
    {
        self.font = [self.font fontWithSize: requiredFontSize];
    }

Voici la nouvelle méthode:

- (CGFloat)requiredFontSize
{
    const CGRect  textBounds = [self textRectForBounds: self.frame];
    const CGFloat maxWidth   = textBounds.size.width;

    if( _originalFontSize == -1 ) _originalFontSize = self.font.pointSize;

    UIFont* font     = self.font;
    CGFloat fontSize = _originalFontSize;

    BOOL found = NO;
    do
    {
        if( font.pointSize != fontSize )
        {
            font = [font fontWithSize: fontSize];
        }

        CGSize size = [self.text sizeWithFont: font];
        if( size.width <= maxWidth )
        {
            found = YES;
            break;
        }

        fontSize -= 1.0;
        if( fontSize < self.minimumFontSize )
        {
            fontSize = self.minimumFontSize;
            break;
        }

    } while( TRUE );

    return( fontSize );
}
10
hvanbrug

J'ai eu le même problème. UITextField a cessé de réduire le texte quand il était trop long, mais au lieu de cela, il s'est redimensionné et a grandi en dehors de ses limites.

La solution qui m'a aidé était de définir width constraint sur un UITextField donné. Après cela, le texte à l'intérieur est devenu plus petit, comme prévu ... (bien sûr, vous devez définir minFontSize et cocher la case "ajuster à la taille" dans le scénario).

Je sais que c'est un peu tard, mais si quelqu'un d'autre trouve cette question via google comme je l'ai fait ... cela pourrait aider.

14
micromanc3r

Je pense que vous souhaitez définir la propriété adjustsFontSizeToFitWidth pour votre UITextField sur YES et spécifier une minimumFontSize. Cela fonctionne pour moi, mais j’ajoute la UITextField par programme - problème d’IB?

8
Matt Powlson

Swift 3.0 façon de redimensionner la police pour l'adapter:

let startFontSize = 14.0
let minFontSize = 7.0

func resizeFont() {
    guard let font = self.font, let text = self.text else {
        return
    }

    let textBounds = self.textRect(forBounds: self.bounds)
    let maxWidth = textBounds.size.width

    for fontSize in stride(from: startFontSize, through: minFontSize, by: -0.5) {
        let size = (text as NSString).size(attributes: [NSFontAttributeName: font.withSize(CGFloat(fontSize))])
        self.font = font.withSize(CGFloat(fontSize))
        if size.width <= maxWidth {
            break
        }
    }
}
1
Jim Conroy

Essayez ceci son travail pour moi (Swift 3.0)

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // bla bla ... anything inside method you want to do
        // reset font size of textfield
        textField.font = UIFont.systemFont(ofSize: CGFloat(15.0))
        var widthOfText: CGFloat = textField.text!.size(attributes: [NSFontAttributeName: textField.font!]).width
        var widthOfFrame: CGFloat = textField.frame.size.width
        // decrease font size until it fits (25 is constant that works for me)
        while (widthOfFrame - 25) < widthOfText {
            let fontSize: CGFloat = textField.font!.pointSize
            textField.font = textField.font?.withSize(CGFloat(fontSize - 0.5))
            widthOfText = (textField.text?.size(attributes: [NSFontAttributeName: textField.font!]).width)!
            widthOfFrame = textField.frame.size.width
        }
        return true
    }
1
vijay
-(BOOL)sizeFontToFit:(NSString*)aString minSize:(float)aMinFontSize maxSize:(float)aMaxFontSize 
{   
float fudgeFactor = 16.0;
float fontSize = aMaxFontSize;

self.font = [self.font fontWithSize:fontSize];

CGSize tallerSize = CGSizeMake(self.frame.size.width-fudgeFactor,kMaxFieldHeight);
CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];

while (stringSize.height >= self.frame.size.height)
       {
       if (fontSize <= aMinFontSize) // it just won't fit
           return NO;

       fontSize -= 1.0;
       self.font = [self.font fontWithSize:fontSize];
       tallerSize = CGSizeMake(self.frame.size.width-fudgeFactor,kMaxFieldHeight);
       stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
       }

return YES; 
}
1
Purva

Mon humble solution à ce problème était la suivante ... (trouver moi-même la taille de police appropriée - à la taille du cadre) je l’ai intégrée à la méthode déléguée de shouldChangeCharactersInRange: replacementString:

-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

 {

    // bla bla ... anything inside method you want to do

    // reset font size of textfield
    textField.font = [FONT_PROXY fontNormalOfSizeNormal];

    CGFloat widthOfText = [textField.text sizeWithAttributes:@{NSFontAttributeName:textField.font}].width;
    CGFloat widthOfFrame = textField.frame.size.width;

    // decrease font size until it fits (25 is constant that works for me)
    while((widthOfFrame - 25) < widthOfText){
        CGFloat fontSize = textField.font.pointSize;
        textField.font = [textField.font fontWithSize:fontSize - 0.5f];
         widthOfText = [textField.text sizeWithAttributes:@{NSFontAttributeName:textField.font}].width;
         widthOfFrame = textField.frame.size.width;
    }


  }
0
Marek Manduch

J'ai eu ce même problème avec UITextFields créé dans StoryBoard dans Xcode 5.0.2, exécutant iOS 7.0.4. J'ai compris que StoryBoard, viewDidLoad ou viewWillAppear ne pouvaient pas modifier la propriété .minimumFontSize, mais qu'elle pouvait était modifiée dans viewDidAppear. Donc, le code suivant a résolu mon problème:

- (void) viewDidAppear:(BOOL)animated  {
    [super viewDidAppear:animated];
    self.myTextField.minimumFontSize = 4.0;
    [self.myTextField setNeedsLayout];
    [self.myTextField layoutIfNeeded];
}
0
user955853

Testé avec XCode8 et Swift 3.0.1 

func getTextfield(view: UIView) -> [UITextField] {
    var results = [UITextField]()
    for subview in view.subviews as [UIView] {
        if let textField = subview as? UITextField {
            results += [textField]
        } else {
            results += getTextfield(view: subview)
        }
    }
    return results
}

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    let allTextFields = getTextfield(view: self.view)
    for textField in allTextFields
    {
        textField.font = UIFont.boldSystemFont(ofSize: 14)
        var widthOfText: CGFloat = textField.text!.size(attributes: [NSFontAttributeName: textField.font!]).width
        var widthOfFrame: CGFloat = textField.frame.size.width
        while (widthOfFrame - 15) < widthOfText { // try here to find the value that fits your needs
            let fontSize: CGFloat = textField.font!.pointSize
            textField.font = textField.font?.withSize(CGFloat(fontSize - 0.5))
            widthOfText = (textField.text?.size(attributes: [NSFontAttributeName: textField.font!]).width)!
            widthOfFrame = textField.frame.size.width
        }
    }
}

J'ai utilisé viewDidLayoutSubviews pour obtenir tous les champs de texte et pour rétracter automatiquement le texte.

Peut-être que quelqu'un aura besoin de ce code.

Pour moi cela fonctionne parfaitement.

Le code provient de @ Marek Manduch sur ce site et de 

@Kunal Kumar sur ce site: Comment obtenir tous les champs de texte depuis une vue dans Swift

0
Skyborg