Tout d'abord, il est très important de noter qu'il existe une grande différence entre UITextView et UILabel en ce qui concerne le rendu du texte. Non seulement UITextView a des encarts sur toutes les bordures, mais la disposition du texte à l'intérieur est également légèrement différente.
Par conséquent, sizeWithFont:
c'est une mauvaise façon d'aller pour UITextViews.
Au lieu de cela, UITextView
elle a une fonction appelée sizeThatFits:
qui retournera la plus petite taille nécessaire pour afficher tout le contenu de l' UITextView
intérieur d'une boîte englobante, que vous pouvez spécifier.
Ce qui suit fonctionnera de la même manière pour iOS 7 et les versions antérieures et n'inclut pour le moment aucune méthode obsolète.
Solution simple
- (CGFloat)textViewHeightForAttributedText: (NSAttributedString*)text andWidth: (CGFloat)width {
UITextView *calculationView = [[UITextView alloc] init];
[calculationView setAttributedText:text];
CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}
Cette fonction prendra a NSAttributedString
et la largeur désirée comme a CGFloat
et retournera la hauteur nécessaire
Solution détaillée
Depuis que j'ai récemment fait quelque chose de similaire, j'ai pensé partager également quelques solutions aux problèmes liés que j'ai rencontrés. J'espère que cela aidera quelqu'un.
Ceci est beaucoup plus détaillé et couvrira les points suivants:
- Bien sûr: définir la hauteur d'un en
UITableViewCell
fonction de la taille nécessaire pour afficher le contenu complet d'un contenuUITextView
- Répondre aux changements de texte (et animer les changements de hauteur de la ligne)
- Garder le curseur à l'intérieur de la zone visible et garder le premier répondant sur le
UITextView
lors du redimensionnement de la UITableViewCell
pendant l'édition
Si vous travaillez avec une vue de table statique ou si vous n'avez qu'un nombre connu de UITextView
s, vous pouvez potentiellement simplifier l'étape 2.
1. Tout d'abord, écrasez heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// check here, if it is one of the cells, that needs to be resized
// to the size of the contained UITextView
if ( )
return [self textViewHeightForRowAtIndexPath:indexPath];
else
// return your normal height here:
return 100.0;
}
2. Définissez la fonction qui a calculé la hauteur nécessaire:
Ajoutez un NSMutableDictionary
(dans cet exemple appelé textViews
) comme variable d'instance à votre UITableViewController
sous - classe.
Utilisez ce dictionnaire pour stocker les références à l'individu UITextViews
comme ceci:
(et oui, indexPaths sont des clés valides pour les dictionnaires )
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Do you cell configuring ...
[textViews setObject:cell.textView forKey:indexPath];
[cell.textView setDelegate: self]; // Needed for step 3
return cell;
}
Cette fonction va maintenant calculer la hauteur réelle:
- (CGFloat)textViewHeightForRowAtIndexPath: (NSIndexPath*)indexPath {
UITextView *calculationView = [textViews objectForKey: indexPath];
CGFloat textViewWidth = calculationView.frame.size.width;
if (!calculationView.attributedText) {
// This will be needed on load, when the text view is not inited yet
calculationView = [[UITextView alloc] init];
calculationView.attributedText = // get the text from your datasource add attributes and insert here
textViewWidth = 290.0; // Insert the width of your UITextViews or include calculations to set it accordingly
}
CGSize size = [calculationView sizeThatFits:CGSizeMake(textViewWidth, FLT_MAX)];
return size.height;
}
3. Activer le redimensionnement lors de la modification
Pour les deux fonctions suivantes, il est important que le délégué de UITextViews
soit défini sur votre UITableViewController
. Si vous avez besoin d'autre chose en tant que délégué, vous pouvez le contourner en effectuant les appels appropriés à partir de là ou en utilisant les hooks NSNotificationCenter appropriés.
- (void)textViewDidChange:(UITextView *)textView {
[self.tableView beginUpdates]; // This will cause an animated update of
[self.tableView endUpdates]; // the height of your UITableViewCell
// If the UITextView is not automatically resized (e.g. through autolayout
// constraints), resize it here
[self scrollToCursorForTextView:textView]; // OPTIONAL: Follow cursor
}
4. Suivez le curseur lors de l'édition
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Cela fera UITableView
défiler jusqu'à la position du curseur, s'il n'est pas à l'intérieur du Rect visible de l'UITableView:
- (void)scrollToCursorForTextView: (UITextView*)textView {
CGRect cursorRect = [textView caretRectForPosition:textView.selectedTextRange.start];
cursorRect = [self.tableView convertRect:cursorRect fromView:textView];
if (![self rectVisible:cursorRect]) {
cursorRect.size.height += 8; // To add some space underneath the cursor
[self.tableView scrollRectToVisible:cursorRect animated:YES];
}
}
5. Ajustez le rect visible, en définissant des encarts
Lors de l'édition, certaines parties de votre UITableView
peuvent être couvertes par le clavier. Si les insertions de tableview ne sont pas ajustées, scrollToCursorForTextView:
ne pourra pas faire défiler jusqu'à votre curseur, s'il se trouve en bas de la tableview.
- (void)keyboardWillShow:(NSNotification*)aNotification {
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, kbSize.height, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
}
- (void)keyboardWillHide:(NSNotification*)aNotification {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.35];
UIEdgeInsets contentInsets = UIEdgeInsetsMake(self.tableView.contentInset.top, 0.0, 0.0, 0.0);
self.tableView.contentInset = contentInsets;
self.tableView.scrollIndicatorInsets = contentInsets;
[UIView commitAnimations];
}
Et dernière partie:
À l'intérieur de votre vue s'est chargée, inscrivez-vous aux notifications pour les modifications du clavier via NSNotificationCenter
:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
S'il vous plaît, ne vous fâchez pas contre moi, pour avoir rendu cette réponse si longue. Même si tout n'est pas nécessaire pour répondre à la question, je crois qu'il y a d'autres personnes à qui ces questions directement liées seront utiles.
METTRE À JOUR:
Comme l'a souligné Dave Haupert, j'ai oublié d'inclure la rectVisible
fonction:
- (BOOL)rectVisible: (CGRect)rect {
CGRect visibleRect;
visibleRect.origin = self.tableView.contentOffset;
visibleRect.origin.y += self.tableView.contentInset.top;
visibleRect.size = self.tableView.bounds.size;
visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
return CGRectContainsRect(visibleRect, rect);
}
J'ai également remarqué que cela scrollToCursorForTextView:
incluait toujours une référence directe à l'un des TextFields de mon projet. Si vous rencontrez un problème pour bodyTextView
ne pas être trouvé, vérifiez la version mise à jour de la fonction.
attributedText
sans spécifier l'alignement de la police, de la couleur et du texte conduit à la définition des valeurs par défaut des attributs NSAttributedString au textView. Dans mon cas, cela provoque l'obtention de différentes hauteurs de la vue de texte pour le même texte.Il existe une nouvelle fonction pour remplacer sizeWithFont, qui est boundingRectWithSize.
J'ai ajouté la fonction suivante à mon projet, qui utilise la nouvelle fonction sur iOS7 et l'ancienne sur iOS inférieure à 7. Elle a fondamentalement la même syntaxe que sizeWithFont:
Vous pouvez ajouter ce IOS_NEWER_OR_EQUAL_TO_7 sur votre fichier prefix.pch dans votre projet comme:
la source
Si vous utilisez UITableViewAutomaticDimension, j'ai une solution très simple (iOS 8 uniquement). Dans mon cas, c'est une vue de table statique, mais je suppose que vous pouvez l'adapter pour des prototypes dynamiques ...
J'ai une sortie de contrainte pour la hauteur de la vue de texte et j'ai implémenté les méthodes suivantes comme ceci:
Mais rappelez - vous : la vue texte doit pouvoir faire défiler, et vous devez configurer vos contraintes de manière à ce qu'elles fonctionnent pour la cote automatique:
L'exemple de cellule le plus basique est:
la source
La réponse de Tim Bodeit est excellente. J'ai utilisé le code de Simple Solution pour obtenir correctement la hauteur de la vue de texte et utiliser cette hauteur dans
heightForRowAtIndexPath
. Mais je n'utilise pas le reste de la réponse pour redimensionner la vue texte. Au lieu de cela, j'écris du code pour changer laframe
vue du texte danscellForRowAtIndexPath
.Tout fonctionne dans iOS 6 et les versions antérieures, mais dans iOS 7, le texte en vue texte ne peut pas être entièrement affiché, même si la
frame
vue de texte est effectivement redimensionnée. (Je n'utilise pasAuto Layout
). Cela devrait être la raison pour laquelle dans iOS 7 il y aTextKit
et la position du texte est contrôlée parNSTextContainer
inUITextView
. Donc, dans mon cas, je dois ajouter une ligne pour définir lesomeTextView
afin de le faire fonctionner correctement dans iOS 7.Comme le dit la documentation, ce que fait cette propriété est:
Si vous la laissez avec la valeur par défaut, après le redimensionnement du
frame
desomeTextView
, la taille dutextContainer
n'est pas modifiée, conduisant au résultat que le texte ne peut être affiché que dans la zone avant le redimensionnement.Et peut-être est-il nécessaire de définir le
scrollEnabled = NO
cas où il y en aurait plus d'untextContainer
, afin que le texte soit redistribué de l'untextContainer
à l'autre.la source
Voici une autre solution qui vise la simplicité et le prototypage rapide :
Installer:
UITextView
avec d'autres contenus.TableCell.h
.UITableView
est associé àTableViewController.h
.Solution:
(1) Ajouter à
TableViewController.m
:(2) Ajouter à
TableCell.m
:Explication:
Donc, ce qui se passe ici est le suivant: chaque vue de texte est liée à la hauteur des cellules du tableau par des contraintes verticales et horizontales - cela signifie que lorsque la hauteur de cellule du tableau augmente, la vue de texte augmente également sa taille. J'ai utilisé une version modifiée du code de @ manecosta pour calculer la hauteur requise d'une vue de texte pour s'adapter au texte donné dans une cellule. Cela signifie qu'un texte avec un nombre X de caractères
frameForText:
retournera une taille qui aura une propriétésize.height
qui correspond à la hauteur requise de la vue du texte.Il ne reste plus qu'à mettre à jour la hauteur de la cellule pour qu'elle corresponde à la hauteur de la vue texte requise. Et ceci est réalisé à
heightForRowAtIndexPath:
. Comme indiqué dans les commentaires, comme ilsize.height
ne s'agit que de la hauteur de la vue texte et non de la cellule entière, il devrait y avoir un décalage ajouté. Dans le cas de l'exemple, cette valeur était de 80.la source
dream.dream
était le texte que je rendais dans la vue texte.Une approche si vous utilisez la mise en page automatique consiste à laisser le moteur de mise en page automatique calculer la taille pour vous. Ce n'est pas l'approche la plus efficace, mais elle est assez pratique (et sans doute la plus précise). Cela devient plus pratique à mesure que la complexité de la disposition de la cellule augmente - par exemple, vous avez soudainement deux vues / champs de texte ou plus dans la cellule.
J'ai répondu à une question similaire avec un exemple complet de dimensionnement des cellules de vue de tableau à l'aide de la disposition automatique, ici:
Comment redimensionner superview pour s'adapter à toutes les sous-vues avec mise en page automatique?
la source
La solution lisse complète est la suivante.
Tout d'abord, nous avons besoin de la classe de cellule avec un textView
Ensuite, nous l'utilisons dans le TableViewController
Ici,
minLines
permet de définir la hauteur minimale pour le textView (pour résister à la réduction de la hauteur par AutoLayout avec UITableViewAutomaticDimension).moveRowAtIndexPath:indexPath:
avec le même indexPath démarre le recalcul et la mise en page de la hauteur de tableViewCell.performWithoutAnimation:
supprime l'effet secondaire (décalage de contenu tableView sautant au début d'une nouvelle ligne lors de la saisie).Il est important de conserver
relativeFrameOriginY
(pascontentOffsetY
!) Pendant la mise à jour de la cellule en raisoncontentSize
des cellules avant que la cellule actuelle ne puisse être modifiée par le calcul de mise en page automatique de manière inattendue. Il supprime les sauts visuels sur la césure du système lors de la saisie de mots longs.Notez que vous ne devez pas définir la propriété
estimatedRowHeight
! Ce qui suit ne fonctionne pasUtilisez uniquement la méthode tableViewDelegate.
=================================================== =========================
Si cela ne vous dérange pas de la liaison faible entre tableView et tableViewCell et de la mise à jour de la géométrie de la tableView à partir de tableViewCell , il est possible de mettre à niveau la
TextInputTableViewCell
classe ci-dessus:la source
La hauteur de votre cellule sera calculée en fonction du contenu d'UILabel, mais tout le texte sera affiché par TextField.
la source
Je pense que de cette façon, vous pouvez compter la hauteur de votre vue de texte, puis redimensionner votre cellule de vue de tableau en fonction de cette hauteur afin que vous puissiez afficher le texte intégral sur la cellule
la source
Version Swift
la source
Si vous souhaitez ajuster automatiquement
UITableViewCell
la hauteur de la base en fonction de la hauteur de la hauteur intérieureUITextView
. Voir ma réponse ici: https://stackoverflow.com/a/45890087/1245231La solution est assez simple et devrait fonctionner depuis iOS 7. Assurez-vous que l'
Scrolling Enabled
option est désactivée pour l'UITextView
intérieurUITableViewCell
du StoryBoard.Ensuite, dans viewDidLoad () de votre UITableViewController, définissez le
tableView.rowHeight = UITableViewAutomaticDimension
ettableView.estimatedRowHeight > 0
tel que:C'est tout.
UITableViewCell
La hauteurUITextView
de l ' intérieur sera automatiquement ajustée en fonction de la hauteur intérieure .la source
Pour iOS 8 et supérieur, vous pouvez simplement utiliser
your_tablview.estimatedrowheight= minheight
tu veuxla source