Question

Existe-t-il un bon moyen d'ajuster la taille d'un UITextView se conformer à son contenu ?Disons par exemple que j'ai un UITextView qui contient une ligne de texte :

"Hello world"

J'ajoute ensuite une autre ligne de texte :

"Goodbye world"

Existe-t-il un bon moyen dans Cocoa Touch d'obtenir le rect qui contiendra toutes les lignes de la vue texte afin que je puisse ajuster la vue parent en conséquence ?

Comme autre exemple, regardez le champ de notes pour les événements dans l'application Calendrier - notez comment la cellule (et le UITextView qu'il contient) se développe pour contenir toutes les lignes de texte dans la chaîne de notes.

Était-ce utile?

La solution

Cela fonctionne à la fois pour iOS 6.1 et iOS 7 :

- (void)textViewDidChange:(UITextView *)textView
{
    CGFloat fixedWidth = textView.frame.size.width;
    CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
    CGRect newFrame = textView.frame;
    newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
    textView.frame = newFrame;
}

Ou dans Swift (fonctionne avec Swift 4.1 dans iOS 11)

let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
textView.frame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)

Si vous souhaitez prendre en charge iOS 6.1, vous devez également :

textview.scrollEnabled = NO;

Autres conseils

Cela ne fonctionne plus sur iOS 7 ou supérieur

Il existe en fait un moyen très simple de redimensionner le UITextView à sa hauteur correcte du contenu.Cela peut être fait en utilisant le UITextView contentSize.

CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

Une chose à noter est que le bon contentSize est uniquement disponible après le UITextView a été ajouté à la vue avec addSubview.Avant cela, il est égal à frame.size

Cela ne fonctionnera pas si la mise en page automatique est activée.Avec la mise en page automatique, l'approche générale consiste à utiliser le sizeThatFits méthode et mettre à jour le constant valeur sur une contrainte de hauteur.

CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;

heightConstraint est une contrainte de mise en page que vous configurez généralement via un IBOutlet en liant la propriété à la contrainte de hauteur créée dans un storyboard.


Juste pour ajouter à cette étonnante réponse, 2014, si vous :

[self.textView sizeToFit];

il y a une différence de comportement avec le iPhone6+ seulement:

enter image description here

Avec le 6+ uniquement (pas les 5 ou 6), il ajoute "une ligne vierge supplémentaire" à UITextView.La « solution RL » résout parfaitement ce problème :

CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;

Il corrige le problème de "ligne supplémentaire" sur 6+.

Pour faire un dimensionnement dynamique UITextView à l'intérieur d'un UITableViewCell, j'ai trouvé que la combinaison suivante fonctionne dans Xcode 6 avec le SDK iOS 8 :

  • Ajouter un UITextView à un UITableViewCell et contraignez-le sur les côtés
  • Met le UITextViewc'est scrollEnabled propriété à NO.Avec le défilement activé, le cadre du UITextView est indépendant de la taille de son contenu, mais avec le défilement désactivé, il existe une relation entre les deux.
  • Si votre tableau utilise la hauteur de ligne par défaut d'origine de 44, il calculera automatiquement les hauteurs de ligne, mais si vous avez modifié la hauteur de ligne par défaut en autre chose, vous devrez peut-être activer manuellement le calcul automatique des hauteurs de ligne dans viewDidLoad:

    tableView.estimatedRowHeight = 150;
    tableView.rowHeight = UITableViewAutomaticDimension;
    

Pour un dimensionnement dynamique en lecture seule UITextViews, c'est tout.Si vous autorisez les utilisateurs à modifier le texte dans votre UITextView, vous devez également :

  • Mettre en œuvre le textViewDidChange: méthode du UITextViewDelegate protocole, et dites au tableView pour se repeindre à chaque fois que le texte est édité :

    - (void)textViewDidChange:(UITextView *)textView;
    {
        [tableView beginUpdates];
        [tableView endUpdates];
    }
    
  • Et n'oubliez pas de définir le UITextView déléguer quelque part, soit dans Storyboard ou dans tableView:cellForRowAtIndexPath:

Rapide :

textView.sizeToFit()

Solution de travail très simple utilisant le code et le storyboard.

Par code

textView.scrollEnabled = false

Par story-board

Décochez la Activer le défilement

enter image description here

Pas besoin de faire autre chose à part ça.

D'après mon expérience (limitée),

- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode

ne respecte pas les caractères de nouvelle ligne, vous pouvez donc vous retrouver avec un texte beaucoup plus court CGSize que ce qui est réellement nécessaire.

- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

semble respecter les nouvelles lignes.

De plus, le texte n'est pas réellement affiché en haut de la page. UITextView.Dans mon code, j'ai défini la nouvelle hauteur du UITextView être 24 pixels plus grand que la hauteur renvoyée par le sizeOfFont méthodes.

Dans iOS6, vous pouvez vérifier le contentSize propriété de UITextView juste après avoir défini le texte.Sous iOS7, cela ne fonctionnera plus.Si vous souhaitez restaurer ce comportement pour iOS7, placez le code suivant dans une sous-classe de UITextView.

- (void)setText:(NSString *)text
{
    [super setText:text];

    if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
        CGRect rect = [self.textContainer.layoutManager usedRectForTextContainer:self.textContainer];
        UIEdgeInsets inset = self.textContainerInset;
        self.contentSize = UIEdgeInsetsInsetRect(rect, inset).size;
    }
}

Je publierai la bonne solution au bas de la page au cas où quelqu'un serait courageux (ou assez désespéré) pour lire jusqu'ici.

Voici le dépôt gitHub pour ceux qui ne veulent pas lire tout ce texte : redimensionnableTextView

Cela fonctionne avec iOS7 (et je pense que cela fonctionnera avec iOS8) et avec la mise en page automatique.Vous n'avez pas besoin de nombres magiques, de désactivation de la mise en page et des trucs comme ça. Solution courte et élégante.

Je pense que tout le code lié aux contraintes devrait aller vers updateConstraints méthode.Alors, créons le nôtre ResizableTextView.

Le premier problème que nous rencontrons ici est que nous ne connaissons pas la taille réelle du contenu avant viewDidLoad méthode.Nous pouvons emprunter un chemin long et bogué et le calculer en fonction de la taille de la police, des sauts de ligne, etc.Mais nous avons besoin d'une solution robuste, nous allons donc faire :

CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

Alors maintenant, nous connaissons la taille réelle du contenu, peu importe où nous sommes :avant ou après viewDidLoad.Ajoutez maintenant une contrainte de hauteur sur textView (via un storyboard ou du code, peu importe comment).Nous ajusterons cette valeur avec notre contentSize.height:

[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
    if (constraint.firstAttribute == NSLayoutAttributeHeight) {
        constraint.constant = contentSize.height;
        *stop = YES;
    }
}];

La dernière chose à faire est de dire à la superclasse de updateConstraints.

[super updateConstraints];

Maintenant, notre classe ressemble à :

RedimensionnableTextView.m

- (void) updateConstraints {
    CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];

    [self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
        if (constraint.firstAttribute == NSLayoutAttributeHeight) {
            constraint.constant = contentSize.height;
            *stop = YES;
        }
    }];

    [super updateConstraints];
}

Jolie et propre, non ?Et vous n'avez pas à gérer ce code dans votre contrôleurs!

Mais attendez! Y PAS D'ANIMATION !

Vous pouvez facilement animer les modifications à apporter textView étirez-vous en douceur.Voici un exemple:

    [self.view layoutIfNeeded];
    // do your own text change here.
    self.infoTextView.text = [NSString stringWithFormat:@"%@, %@", self.infoTextView.text, self.infoTextView.text];
    [self.infoTextView setNeedsUpdateConstraints];
    [self.infoTextView updateConstraintsIfNeeded];
    [UIView animateWithDuration:1 delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{
        [self.view layoutIfNeeded];
    } completion:nil];

As-tu essayé [textView sizeThatFits:textView.bounds] ?

Modifier:sizeThatFits renvoie la taille mais ne redimensionne pas réellement le composant.Je ne sais pas si c'est ce que tu veux, ou si [textView sizeToFit] c'est plus ce que vous recherchiez.Dans les deux cas, je ne sais pas si cela s’adaptera parfaitement au contenu comme vous le souhaitez, mais c’est la première chose à essayer.

Une autre méthode consiste à trouver la taille qu'une chaîne particulière prendra en utilisant le NSString méthode:

-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

Cela renvoie la taille du rectangle qui correspond à la chaîne donnée avec la police donnée.Entrez une taille avec la largeur souhaitée et une hauteur maximale, puis vous pourrez regarder la hauteur renvoyée pour s'adapter au texte.Il existe une version qui vous permet également de spécifier le mode de saut de ligne.

Vous pouvez ensuite utiliser la taille renvoyée pour modifier la taille de votre vue afin qu'elle s'adapte.

Si vous n'avez pas le UITextView pratique (par exemple, vous dimensionnez des cellules d'une vue tableau), vous devrez calculer la taille en mesurant la chaîne, puis en tenant compte des 8 pts de remplissage de chaque côté d'un UITextView.Par exemple, si vous connaissez la largeur souhaitée de votre affichage de texte et souhaitez déterminer la hauteur correspondante :

NSString * string = ...;
CGFloat textViewWidth = ...;
UIFont * font = ...;

CGSize size = CGSizeMake(textViewWidth - 8 - 8, 100000);
size.height = [string sizeWithFont:font constrainedToSize:size].height + 8 + 8;

Ici, chaque 8 représente l'un des quatre bords rembourrés, et 100 000 sert simplement de très grande taille maximale.

En pratique, vous souhaiterez peut-être ajouter un supplément font.leading à la hauteur;cela ajoute une ligne vide sous votre texte, ce qui peut être plus beau s'il y a des contrôles visuellement lourds directement sous la vue texte.

Les choses suivantes suffisent :

  1. N'oubliez pas de définir défilement activé à NON pour votre UITextView:

enter image description here

  1. Définissez correctement les contraintes de mise en page automatique.

Vous pouvez même utiliser UITableViewAutomaticDimension.

Nous pouvons le faire par contraintes.

  1. Définissez les contraintes de hauteur pour UITextView.enter image description here

2.Créez IBOutlet pour cette contrainte de hauteur.

 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;

3.n'oubliez pas de définir un délégué pour votre vue de texte.

4.

-(void)textViewDidChange:(UITextView *)textView
{
    CGFloat fixedWidth = textView.frame.size.width;
    CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
    CGRect newFrame = textView.frame;
    newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
    NSLog(@"this is updating height%@",NSStringFromCGSize(newFrame.size));
    [UIView animateWithDuration:0.2 animations:^{
                  _txtheightconstraints.constant=newFrame.size.height;
    }];

}

puis mettez à jour votre contrainte comme ceci :)

En combinaison avec la réponse de Mike McMaster, vous voudrez peut-être faire quelque chose comme :

[myTextView setDelegate: self];

...

- (void)textViewDidChange:(UITextView *)textView {
  if (myTextView == textView) {
     // it changed.  Do resizing here.
  }
}

J'ai découvert un moyen de redimensionner la hauteur d'un champ de texte en fonction du texte qu'il contient et également de disposer une étiquette en dessous en fonction de la hauteur du champ de texte !Voici le code.

UITextView *_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, 300, 10)];
NSString *str = @"This is a test text view to check the auto increment of height of a text view. This is only a test. The real data is something different.";
_textView.text = str;

[self.view addSubview:_textView];
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;

UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 5 + frame.origin.y + frame.size.height, 300, 20)];
lbl.text = @"Hello!";
[self.view addSubview:lbl];

Les gars qui utilisent la mise en page automatique et votre sizetofit ne fonctionnent pas, alors veuillez vérifier votre contrainte de largeur une fois.Si vous avez manqué la contrainte de largeur alors la hauteur sera précise.

Pas besoin d'utiliser une autre API.une seule ligne résoudrait tout le problème.

[_textView sizeToFit];

Ici, je ne me préoccupais que de la hauteur, en gardant la largeur fixe et j'avais manqué la contrainte de largeur de mon TextView dans le storyboard.

Et cela devait montrer le contenu dynamique des services.

J'espère que cela pourrait aider..

À partir d'iOS 8, il est possible d'utiliser les fonctionnalités de mise en page automatique d'un UITableView pour redimensionner automatiquement un UITextView sans aucun code personnalisé.J'ai mis un projet dans github cela le démontre en action, mais voici la clé :

  1. Le défilement de UITextView doit être désactivé, ce que vous pouvez faire par programme ou via le générateur d'interface.Il ne sera pas redimensionné si le défilement est activé, car le défilement vous permet d'afficher un contenu plus volumineux.
  2. Dans viewDidLoad pour UITableViewController, vous devez définir une valeur pourestimateRowHeight, puis définir la valeur rowHeight à UITableViewAutomaticDimension.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.estimatedRowHeight = self.tableView.rowHeight;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}
  1. La cible de déploiement du projet doit être iOS 8 ou version ultérieure.

Cela a bien fonctionné lorsque j'avais besoin de créer du texte dans un UITextView s'adapter à une zone spécifique :

// The text must already be added to the subview, or contentviewsize will be wrong.

- (void) reduceFontToFit: (UITextView *)tv {
    UIFont *font = tv.font;
    double pointSize = font.pointSize;

    while (tv.contentSize.height > tv.frame.size.height && pointSize > 7.0) {
        pointSize -= 1.0;
        UIFont *newFont = [UIFont fontWithName:font.fontName size:pointSize];
        tv.font = newFont;
    }
    if (pointSize != font.pointSize)
        NSLog(@"font down to %.1f from %.1f", pointSize, tv.font.pointSize);
}

voici la version rapide de @jhibberd

    let cell:MsgTableViewCell! = self.tableView.dequeueReusableCellWithIdentifier("MsgTableViewCell", forIndexPath: indexPath) as? MsgTableViewCell
    cell.msgText.text = self.items[indexPath.row]
    var fixedWidth:CGFloat = cell.msgText.frame.size.width
    var size:CGSize = CGSize(width: fixedWidth,height: CGFloat.max)
    var newSize:CGSize = cell.msgText.sizeThatFits(size)
    var newFrame:CGRect = cell.msgText.frame;
    newFrame.size = CGSizeMake(CGFloat(fmaxf(Float(newSize.width), Float(fixedWidth))), newSize.height);
    cell.msgText.frame = newFrame
    cell.msgText.frame.size = newSize        
    return cell

J'ai examiné toutes les réponses et toutes conservent une largeur fixe et n'ajustent que la hauteur.Si vous souhaitez ajuster également la largeur vous pouvez très facilement utiliser cette méthode :

donc lors de la configuration de votre affichage de texte, désactivez le défilement

textView.isScrollEnabled = false

puis dans la méthode déléguée func textViewDidChange(_ textView: UITextView) ajoutez ce code:

func textViewDidChange(_ textView: UITextView) {
    let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
    textView.frame = CGRect(origin: textView.frame.origin, size: newSize)
}

Les sorties:

enter image description here

enter image description here

désactiver le défilement

ajouter des contraintes

et ajoutez votre texte

[yourTextView setText:@"your text"];
[yourTextView layoutIfNeeded];

si tu utilises UIScrollView vous devriez également ajouter ceci ;

[yourScrollView layoutIfNeeded];

-(void)viewDidAppear:(BOOL)animated{
    CGRect contentRect = CGRectZero;

    for (UIView *view in self.yourScrollView.subviews) {
         contentRect = CGRectUnion(contentRect, view.frame);
    }
    self.yourScrollView.contentSize = contentRect.size;
}

Pour iOS 7.0, au lieu de définir le frame.size.height au contentSize.height (qui ne fait rien actuellement) utilise [textView sizeToFit].

Voir cette question.

J'espère que cela t'aides:

- (void)textViewDidChange:(UITextView *)textView {
  CGSize textSize = textview.contentSize;
  if (textSize != textView.frame.size)
      textView.frame.size = textSize;
}

si quelqu'un d'autre arrive ici, cette solution fonctionne pour moi, 1"Ronnie Liew"+4"user63934" (Mon texte arrive du service Web) :notez le 1000 (rien ne peut être si gros "dans mon cas")

UIFont *fontNormal = [UIFont fontWithName:FONTNAME size:FONTSIZE];

NSString *dealDescription = [client objectForKey:@"description"];

//4
CGSize textSize = [dealDescription sizeWithFont:fontNormal constrainedToSize:CGSizeMake(containerUIView.frame.size.width, 1000)];

CGRect dealDescRect = CGRectMake(10, 300, containerUIView.frame.size.width, textSize.height);

UITextView *dealDesc = [[[UITextView alloc] initWithFrame:dealDescRect] autorelease];

dealDesc.text = dealDescription;
//add the subview to the container
[containerUIView addSubview:dealDesc];

//1) after adding the view
CGRect frame = dealDesc.frame;
frame.size.height = dealDesc.contentSize.height;
dealDesc.frame = frame;

Et c'est...Acclamations

La meilleure façon que j'ai découverte de redimensionner la hauteur de UITextView en fonction de la taille du texte.

CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
                       constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX)];

ou Vous pouvez UTILISER

CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
                       constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX) lineBreakMode:NSLineBreakByTruncatingTail];

Pour ceux qui souhaitent que la vue texte monte réellement et maintienne la position de la ligne inférieure

CGRect frame = textView.frame;
frame.size.height = textView.contentSize.height;

if(frame.size.height > textView.frame.size.height){
    CGFloat diff = frame.size.height - textView.frame.size.height;
    textView.frame = CGRectMake(0, textView.frame.origin.y - diff, textView.frame.size.width, frame.size.height);
}
else if(frame.size.height < textView.frame.size.height){
    CGFloat diff = textView.frame.size.height - frame.size.height;
    textView.frame = CGRectMake(0, textView.frame.origin.y + diff, textView.frame.size.width, frame.size.height);
}

Le seul code qui fonctionnera est celui qui utilise « SizeToFit » comme dans la réponse de jhibberd ci-dessus, mais en réalité, il ne répondra que si vous l'appelez. AfficherDidAppear ou connectez-le à l'événement de modification de texte UITextView.

Sur la base de la réponse de Nikita Took, je suis arrivé à la solution suivante dans Swift qui fonctionne sur iOS 8 avec mise en page automatique :

    descriptionTxt.scrollEnabled = false
    descriptionTxt.text = yourText

    var contentSize = descriptionTxt.sizeThatFits(CGSizeMake(descriptionTxt.frame.size.width, CGFloat.max))
    for c in descriptionTxt.constraints() {
        if c.isKindOfClass(NSLayoutConstraint) {
            var constraint = c as! NSLayoutConstraint
            if constraint.firstAttribute == NSLayoutAttribute.Height {
                constraint.constant = contentSize.height
                break
            }
        }
    }

Réponse rapide :Le code suivant calcule la hauteur de votre textView.

                let maximumLabelSize = CGSize(width: Double(textView.frame.size.width-100.0), height: DBL_MAX)
                let options = NSStringDrawingOptions.TruncatesLastVisibleLine | NSStringDrawingOptions.UsesLineFragmentOrigin
                let attribute = [NSFontAttributeName: textView.font!]
                let str = NSString(string: message)
                let labelBounds = str.boundingRectWithSize(maximumLabelSize,
                    options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                    attributes: attribute,
                    context: nil)
                let myTextHeight = CGFloat(ceilf(Float(labelBounds.height)))

Vous pouvez maintenant définir la hauteur de votre textView sur myTextHeight

Voici la réponse si vous avez besoin de redimensionner textView et tableViewCell dynamiquement dans staticTableView

[https://stackoverflow.com/a/43137182/5360675][1]

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top