Comment dimensionner UITextView par rapport à son contenu?

y a-t-il une bonne façon d'ajuster la taille d'un UITextView pour 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"

y a-t-il un bon moyen dans Cocoa Touch pour obtenir le rect qui tiendra toutes les lignes dans la vue texte afin que je puisse ajuster la vue parent en conséquence?

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

475
demandé sur Alok 2008-09-08 23:21:19
la source

30 ответов

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 voulez un support pour iOS 6.1 alors vous devez aussi:

textview.scrollEnabled = NO;
542
répondu jhibberd 2018-06-13 02:46:14
la source

cela ne fonctionne plus sur iOS 7 ou plus

il y a en fait un moyen très facile de redimensionner le UITextView à sa hauteur correcte du contenu. Il 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 contentSize correct est seulement disponible après le UITextView a été ajouté à la vue avec addSubview . Avant qu'il soit égal à frame.size

cela ne fonctionnera pas si la mise en page automatique est activée. Avec la disposition automatique, l'approche générale est d'utiliser la méthode sizeThatFits et de mettre à jour la valeur constant 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 typiquement via un IBOutlet en liant la propriété à la contrainte de hauteur créée dans un storyboard.


juste pour ajouter à ceci réponse étonnante, 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+ seulement (pas le 5s ou 6) Il ajoute" une ligne blanche de plus " à L'UITextView. La" solution RL "corrige parfaitement cette situation:

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

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

570
répondu Ronnie Liew 2017-09-29 13:37:59
la source

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

  • Ajouter un UITextView à un UITableViewCell et le contraindre aux côtés
  • fixe la UITextView 's scrollEnabled propriété à NO . Avec le défilement activé, le cadre du UITextView est indépendant de sa taille de contenu, mais avec le défilement désactivé, il y a un la relation entre les deux.
  • si votre table utilise la hauteur de ligne originale par défaut de 44, alors il calculera automatiquement les hauteurs de ligne, mais si vous avez changé la hauteur de ligne par défaut à quelque chose d'autre, vous pouvez avoir besoin d'activer manuellement auto-calcul des hauteurs de ligne dans viewDidLoad :

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

Pour la lecture seule de dimensionnement dynamique UITextView s, c'est tout. Si vous autorisez les utilisateurs à modifier texte dans votre UITextView , vous devez également:

  • implémenter la méthode textViewDidChange: du protocole UITextViewDelegate , et dire au tableView de se repeindre chaque fois que le texte est édité:

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

85
répondu Brett Donald 2017-06-28 11:37:42
la source

Swift:

textView.sizeToFit()
53
répondu Juan Boero 2016-08-25 00:43:42
la source

Juste mis

Par Code

textView.scrollEnabled = false

Par Storyboard

enter image description here

pas besoin de faire autre chose.

35
répondu Alok 2018-05-29 11:34:28
la source

Dans mon (limitée) de l'expérience,

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

ne respecte pas les caractères newline, de sorte que vous pouvez finir avec beaucoup plus court CGSize que ce qui est réellement requis.

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

semble respecter les nouvelles lignes.

en outre, le texte n'est pas réellement rendu au sommet du UITextView . Dans mon code, j'ai placé la nouvelle hauteur du UITextView à 24 pixels de plus que la hauteur retournée par le sizeOfFont méthode.

24
répondu user63934 2013-06-01 16:47:24
la source

dans iOS6, vous pouvez vérifier la propriété contentSize D'UITextView juste après avoir défini le texte. Dans iOS7, cela ne fonctionnera plus. Si vous voulez restaurer ce comportement pour iOS7, placez le code suivant dans une sous-classe D'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;
    }
}
22
répondu phatmann 2014-04-13 02:19:34
la source

je vais poster la bonne solution au bas de la page dans le cas où quelqu'un est courageux (ou désespéré assez) de lire à ce point.

voici GitHub repo pour ceux qui ne veulent pas lire tout ce texte: resizableTextView

cela fonctionne avec iOs7 (et je crois que cela fonctionnera avec iOs8) et avec autolayout. Vous n'avez pas besoin de numéros magiques, de mise en page désactivée et des trucs comme ça. Court et solution élégante.

je pense que tout le code lié aux contraintes devrait aller à la méthode updateConstraints . Alors, faisons notre propre ResizableTextView .

le premier problème que nous rencontrons ici est que nous ne connaissons pas la taille réelle du contenu avant la méthode viewDidLoad . Nous pouvons prendre la route longue et buggy et le calculer basé sur la taille de la police, les sauts de ligne, etc. Mais nous avons besoin d'une solution robuste, donc nous allons faire:

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

donc maintenant nous connaître le contenu réel peu importe où nous sommes: avant ou après viewDidLoad . Maintenant, ajoutez une contrainte de hauteur sur textView (via storyboard ou 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 à superclass updateConstraints .

[super updateConstraints];

maintenant notre classe ressemble à:

ResizableTextView.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 controllers !

mais attendez! Y PAS D'ANIMATION!

vous pouvez facilement animer les changements pour faire textView s'étirer 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];
18
répondu Nikita Took 2014-07-25 11:43:39
la source

avez-vous essayé [textView sizeThatFits:textView.bounds] ?

Edit: sizeThatFits renvoie la taille mais ne redimensionne pas réellement le composant. Je ne suis pas sûr si c'est ce que vous voulez, ou si [textView sizeToFit] est plus ce que vous recherchez. Dans les deux cas, je ne sais pas si il sera parfaitement le contenu comme vous le souhaitez, mais c'est la première chose à essayer.

12
répondu Mike McMaster 2008-09-09 00:45:44
la source

une autre méthode est la recherche de la taille d'une chaîne particulière prendra en utilisant la NSString méthode:

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

Cette fonction renvoie la taille du rectangle qui correspond à la chaîne avec la police. Passez dans une taille avec la largeur désirée et une hauteur maximale, puis vous pouvez regarder la hauteur retournée pour ajuster le texte. Il y a une version qui vous permet de spécifier le mode line break.

vous pouvez alors utilisez la taille retournée pour changer la taille de votre vue pour s'adapter.

9
répondu Code Addict 2013-06-01 16:47:40
la source

si vous n'avez pas le UITextView à portée de main (par exemple, vous dimensionnez les cellules de vue de table), vous devrez calculer la taille en mesurant la chaîne, puis en tenant compte des 8 pt de rembourrage sur chaque côté d'un UITextView . Par exemple, si vous connaissez la largeur désirée de votre vue texte et que vous voulez calculer 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 est l'un des quatre bords rembourrés, et 100000 sert juste comme un très grand maximum taille.

dans la pratique, vous pouvez ajouter un font.leading supplémentaire à la hauteur; ceci ajoute une ligne vide au-dessous de votre texte, qui peut sembler mieux s'il ya des contrôles visuellement lourds directement sous la vue texte.

8
répondu Brent Royal-Gordon 2013-06-01 16:48:03
la source

les choses suivantes sont suffisantes:

  1. n'oubliez pas de mettre scrolling activé à NON pour votre UITextView :

enter image description here

  1. définir correctement les contraintes de mise en page automatique.

vous pouvez même utiliser UITableViewAutomaticDimension .

7
répondu Bartłomiej Semańczyk 2015-11-02 13:18:23
la source

nous pouvons le faire par contraintes .

  1. définir 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 délégué pour votre textview.

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:)

7
répondu Kishore Kumar 2016-03-04 10:16:20
la source

combiné avec la réponse de Mike McMaster, vous pourriez vouloir faire quelque chose comme:

[myTextView setDelegate: self];

...

- (void)textViewDidChange:(UITextView *)textView {
  if (myTextView == textView) {
     // it changed.  Do resizing here.
  }
}
6
répondu Olie 2008-11-06 07:31:12
la source

j'ai trouvé un moyen de redimensionner la hauteur d'un champ de texte selon le texte à l'intérieur et également organiser une étiquette ci-dessous sur la base 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];
6
répondu dheeraj 2011-03-14 13:13:32
la source

les gars utilisant autolayout et votre sizetofit ne fonctionne pas, alors s'il vous plaît 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. juste une ligne qui permettrait de résoudre tous les problème.

[_textView sizeToFit];

ici, Je ne me souciais que de la hauteur, en gardant la largeur fixe et en ayant manqué la contrainte de largeur de mon TextView en storyboard.

et c'était montrer le contenu dynamique des services.

J'espère que cela pourrait aider..

6
répondu Swaroop S 2015-01-02 09:58:22
la source

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

  1. L'UITextView doit avoir désactivé le défilement, ce que vous pouvez faire par programmation ou via le constructeur de l'interface. Il ne se redimensionnera pas si le scrolling est activé parce que le scrolling vous permet afficher plus de contenu.
  2. dans viewDidLoad pour le Controller Uitable ViewController, vous devez définir une valeur pour estimatedRowHeight et ensuite définir le rowHeight à UITableViewAutomaticDimension .

- (void)viewDidLoad {
    [super viewDidLoad];
    self.tableView.estimatedRowHeight = self.tableView.rowHeight;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
}
  1. l'objectif de déploiement du projet doit être égal ou supérieur à 8.
6
répondu Chuck Krutsinger 2015-08-17 09:00:42
la source

cela a bien fonctionné quand j'ai eu besoin de faire 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);
}
4
répondu Bill Cheswick 2013-06-01 16:48:12
la source

voici la version swift 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
4
répondu Fareed Alnamrouti 2015-03-07 19:02:09
la source

pour iOS 7.0, au lieu de frame.size.height pour contentSize.height (qui ne fait actuellement rien) utiliser [textView sizeToFit] .

voir cette question .

3
répondu Stian Høiland 2017-05-23 15:02:46
la source

j'ai passé en revue toutes les réponses et toutes conservent une largeur fixe et ajustent uniquement la hauteur. Si vous souhaitez ajuster la largeur, vous pouvez très facilement utiliser cette méthode:

donc, lors de la configuration de votre vue texte, définissez scroll désactivé

textView.isScrollEnabled = false

et ensuite dans la méthode de délégué func textViewDidChange(_ textView: UITextView) ajouter 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)
}

sorties:

enter image description here

enter image description here

3
répondu Peter Stajger 2017-03-21 17:12:23
la source

désactiver le défilement

ajouter constaints

et ajouter votre texte

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

si vous utilisez UIScrollView vous devez ajouter ceci aussi;

[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;
}
3
répondu alicanozkara 2018-01-17 11:31:20
la source

Espérons que cela aide:

- (void)textViewDidChange:(UITextView *)textView {
  CGSize textSize = textview.contentSize;
  if (textSize != textView.frame.size)
      textView.frame.size = textSize;
}
1
répondu Dr. Marty 2010-03-17 20:31:32
la source

si quelqu'un d'autre vient ici, Cette solution fonctionne pour moi, 1"Ronnie Liew" +4 "user63934" (mon texte arrive du service web): remarque le 1000 (rien ne peut être si grand "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-à-dire... Cheers

1
répondu Alejo JM 2012-07-30 05:56:34
la source

le meilleur moyen que j'ai trouvé pour re-dimensionner la hauteur de L'UITextView selon 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];
1
répondu Manju 2013-09-06 10:32:29
la source

Pour ceux qui veulent le textview à fait déplacer et maintenir le bas de ligne en position

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);
}
1
répondu Gal Blank 2014-12-01 00:43:46
la source

le seul code qui fonctionnera est celui qui utilise 'SizeToFit' comme dans la réponse de jhibberd ci-dessus, mais en fait il ne sera pas décroché à moins que vous l'appeliez dans ViewDidAppear ou le télégraphiez à UITextView text changed event.

1
répondu Mohammad Zekrallah 2015-04-08 11:25:57
la source

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

    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
            }
        }
    }
1
répondu Apfelsaft 2015-05-13 15:46:46
la source

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

maintenant vous pouvez définir la hauteur de votre textView à myTextHeight

1
répondu RawMean 2015-06-18 04:55:25
la source

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

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

1
répondu Volodymyr Nazarkevych 2017-05-23 15:26:27
la source

Autres questions sur