Comment puis-je calculer la hauteur d'un UITableViewCell avec un UITextView dans iOS 7?
J'ai trouvé beaucoup de réponses sur des questions similaires, mais sizeWithFont:
prend part à toutes les solutions et cette méthode est déconseillée!
Je sais que je dois utiliser - (CGFloat)tableView:heightForRowAtIndexPath:
mais comment puis-je calculer la hauteur dont mon TextView a besoin pour afficher tout le texte?
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. UITextView comporte non seulement des encarts sur toutes les bordures, mais la disposition du texte est légèrement différente.
Par conséquent, sizeWithFont:
est un mauvais moyen d’utiliser UITextViews.
Au lieu de cela, UITextView
a lui-même une fonction appelée sizeThatFits:
qui renvoie la plus petite taille nécessaire pour afficher tout le contenu de la UITextView
à l'intérieur d'un cadre de sélection que vous pouvez spécifier.
Ce qui suit fonctionnera de la même manière pour iOS 7 et les versions plus anciennes et, à l'heure actuelle, n'inclut aucune méthode, qui est obsolète.
- (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 prend un NSAttributedString
et la largeur souhaitée sous la forme CGFloat
et renvoie la hauteur nécessaire
Depuis que j'ai récemment fait quelque chose de similaire, je pensais partager quelques solutions aux problèmes que je rencontrais. J'espère que cela aidera quelqu'un.
C'est beaucoup plus en profondeur et couvrira les éléments suivants:
UITableViewCell
en fonction de la taille requise pour afficher tout le contenu d'un contenu UITextView
UITextView
lors du redimensionnement de la UITableViewCell
lors de l'édition Si vous travaillez avec une vue de table statique ou que vous ne disposez que d'un nombre connu de UITextView
s, vous pouvez potentiellement simplifier l'étape 2 beaucoup plus simplement.
- (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;
}
Ajoutez une NSMutableDictionary
(dans cet exemple appelée textViews
) en tant que variable d'instance à votre sous-classe UITableViewController
.
Utilisez ce dictionnaire pour stocker les références à la personne 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;
}
Pour les deux fonctions suivantes, il est important que le délégué du UITextViews
soit défini sur votre UITableViewController
. Si vous avez besoin de quelque chose d'autre en tant que délégué, vous pouvez le contourner en passant les appels appropriés à partir de là ou en utilisant les points d'ancrage 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
}
- (void)textViewDidBeginEditing:(UITextView *)textView {
[self scrollToCursorForTextView:textView];
}
Ceci fera défiler la UITableView
jusqu'à la position du curseur, si elle ne se trouve pas dans le rect visible de la 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];
}
}
Pendant l’édition, certaines parties de votre UITableView
peuvent être couvertes par le clavier. Si les espaces insérés dans les vues de table ne sont pas ajustés, scrollToCursorForTextView:
ne pourra pas faire défiler le curseur jusqu'à votre curseur, s'il se trouve en bas de la table.
- (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:
Dans votre vue s'est chargée, inscrivez-vous pour recevoir les notifications de 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];
}
Comme Dave Haupert l'a fait remarquer, j'ai oublié d'inclure la fonction rectVisible
:
- (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 aussi remarqué que scrollToCursorForTextView:
incluait toujours une référence directe à l'un des TextFields de mon projet. Si vous avez un problème avec bodyTextView
introuvable, vérifiez la version mise à jour de la fonction.
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 essentiellement la même syntaxe que sizeWithFont:
-(CGSize)text:(NSString*)text sizeWithFont:(UIFont*)font constrainedToSize:(CGSize)size{
if(IOS_NEWER_OR_EQUAL_TO_7){
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
nil];
CGRect frame = [text boundingRectWithSize:size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributesDictionary
context:nil];
return frame.size;
}else{
#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
return [text sizeWithFont:font constrainedToSize:size];
#pragma clang diagnostic pop
}
}
Vous pouvez ajouter cela IOS_NEWER_OR_EQUAL_TO_7 sur votre fichier prefix.pch dans votre projet en tant que:
#define IOS_NEWER_OR_EQUAL_TO_7 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 7.0 )
Si vous utilisez UITableViewAutomaticDimension, j'ai une solution très simple (iOS 8 uniquement). Dans mon cas, il s’agit d’une vue de table statique, mais je suppose que vous pourriez l’adapter à des prototypes dynamiques ...
J'ai un exutoire de contrainte pour la hauteur de la vue texte et j'ai implémenté les méthodes suivantes comme ceci:
// Outlets
@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewHeight;
// Implementation
#pragma mark - Private Methods
- (void)updateTextViewHeight {
self.textViewHeight.constant = self.textView.contentSize.height + self.textView.contentInset.top + self.textView.contentInset.bottom;
}
#pragma mark - View Controller Overrides
- (void)viewDidLoad {
[super viewDidLoad];
[self updateTextViewHeight];
}
#pragma mark - TableView Delegate & Datasource
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 80;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
#pragma mark - TextViewDelegate
- (void)textViewDidChange:(UITextView *)textView {
[self.tableView beginUpdates];
[self updateTextViewHeight];
[self.tableView endUpdates];
}
mais rappelez-vous: la vue texte doit être déroulante et vous devez configurer vos contraintes de sorte qu'elles fonctionnent pour la dimension automatique:
L'exemple de cellule le plus élémentaire est:
La réponse de Tim Bodeit est excellente. J'ai utilisé le code de solution simple 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 du texte. Au lieu de cela, j'écris du code pour changer la frame
de la vue de texte dans cellForRowAtIndexPath
.
Tout fonctionne dans iOS 6 et versions ultérieures, mais dans iOS 7, le texte en affichage texte ne peut pas être entièrement affiché même si la frame
de l'affichage texte est bien redimensionnée. (Je n'utilise pas Auto Layout
). Cela devrait être la raison pour laquelle dans iOS 7 il y a TextKit
et la position du texte est contrôlée par NSTextContainer
dans UITextView
. Donc, dans mon cas, je dois ajouter une ligne pour définir la someTextView
afin de la faire fonctionner correctement dans iOS 7.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) {
someTextView.textContainer.heightTracksTextView = YES;
}
Comme le dit la documentation, ce que fait cette propriété est:
Détermine si le destinataire ajuste la hauteur de son rectangle de délimitation lorsque sa vue texte est redimensionnée. Valeur par défaut: NO.
Si vous laissez la valeur par défaut, après avoir redimensionné la frame
de someTextView
, la taille de la textContainer
ne sera pas modifiée, ce qui entraînera que le texte ne peut être affiché que dans la zone. avant de redimensionner.
Et peut-être est-il nécessaire de définir le scrollEnabled = NO
au cas où il y aurait plus d'un textContainer
, de sorte que le texte sera refondu d'un textContainer
à un autre.
Voici une autre solution qui vise la simplicité et le prototypage rapide :
Configuration:
UITextView
avec d'autres contenus.TableCell.h
.UITableView
est associé à TableViewController.h
.Solution:
(1) Ajouter à TableViewController.m
:
// This is the method that determines the height of each cell.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// I am using a helper method here to get the text at a given cell.
NSString *text = [self getTextAtIndex:indexPath];
// Getting the height needed by the dynamic text view.
CGSize size = [self frameForText:text sizeWithFont:nil constrainedToSize:CGSizeMake(300.f, CGFLOAT_MAX)];
// Return the size of the current row.
// 80 is the minimum height! Update accordingly - or else, cells are going to be too thin.
return size.height + 80;
}
// Think of this as some utility function that given text, calculates how much
// space would be needed to fit that text.
- (CGSize)frameForText:(NSString *)text sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
{
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
nil];
CGRect frame = [text boundingRectWithSize:size
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:attributesDictionary
context:nil];
// This contains both height and width, but we really care about height.
return frame.size;
}
// Think of this as a source for the text to be rendered in the text view.
// I used a dictionary to map indexPath to some dynamically fetched text.
- (NSString *) getTextAtIndex: (NSIndexPath *) indexPath
{
return @"This is stubbed text - update it to return the text of the text view.";
}
(2) Ajouter à TableCell.m
:
// This method will be called when the cell is initialized from the storyboard
// prototype.
- (void)awakeFromNib
{
// Assuming TextView here is the text view in the cell.
TextView.scrollEnabled = YES;
}
Explication:
Voici donc ce qui se passe: 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 la cellule de tableau augmente, la vue du 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 afin qu'elle corresponde au texte donné dans une cellule. Cela signifie donc que, étant donné un texte avec un nombre X de caractères, frameForText:
renverra une taille qui aura une propriété size.height
correspondant à la hauteur requise de la vue texte.
Il ne reste plus qu'à mettre à jour la hauteur de la cellule pour qu'elle corresponde à celle de la vue de texte requise. Et ceci est réalisé à heightForRowAtIndexPath:
. Comme indiqué dans les commentaires, étant donné que size.height
ne représente que la hauteur de la vue texte et non la cellule entière, un décalage doit y être ajouté. Dans le cas de l'exemple, cette valeur était 80.
Une approche si vous utilisez l'autolayout est de laisser le moteur d'autolayout calculer la taille pour vous. Ce n’est pas l’approche la plus efficace, mais c’est plutôt pratique (et sans doute la plus précise). Cela devient plus pratique à mesure que la disposition de la cellule se complexifie - par ex. tout à coup, vous avez deux ou plusieurs vues de texte/champs dans la cellule.
J'ai répondu à une question similaire avec un échantillon complet de la taille des cellules tableview à l'aide de la disposition automatique, ici:
Comment redimensionner superview pour s'adapter à toutes les sous-vues avec autolayout?
La solution lisse complète est la suivante.
Premièrement, nous avons besoin de la classe de cellules avec un textView
@protocol TextInputTableViewCellDelegate <NSObject>
@optional
- (void)textInputTableViewCellTextWillChange:(TextInputTableViewCell *)cell;
- (void)textInputTableViewCellTextDidChange:(TextInputTableViewCell *)cell;
@end
@interface TextInputTableViewCell : UITableViewCell
@property (nonatomic, weak) id<TextInputTableViewCellDelegate> delegate;
@property (nonatomic, readonly) UITextView *textView;
@property (nonatomic) NSInteger minLines;
@property (nonatomic) CGFloat lastRelativeFrameOriginY;
@end
#import "TextInputTableViewCell.h"
@interface TextInputTableViewCell () <UITextViewDelegate> {
NSLayoutConstraint *_heightConstraint;
}
@property (nonatomic) UITextView *textView;
@end
@implementation TextInputTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
_textView = [UITextView new];
_textView.translatesAutoresizingMaskIntoConstraints = NO;
_textView.delegate = self;
_textView.scrollEnabled = NO;
_textView.font = CELL_REG_FONT;
_textView.textContainer.lineFragmentPadding = 0.0;
_textView.textContainerInset = UIEdgeInsetsZero;
[self.contentView addSubview:_textView];
[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
_heightConstraint = [NSLayoutConstraint constraintWithItem: _textView
attribute: NSLayoutAttributeHeight
relatedBy: NSLayoutRelationGreaterThanOrEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 0.0
constant: (_textView.font.lineHeight + 15)];
_heightConstraint.priority = UILayoutPriorityRequired - 1;
[_textView addConstraint:_heightConstraint];
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
self.minLines = 1;
}
- (void)setMinLines:(NSInteger)minLines {
_heightConstraint.constant = minLines * _textView.font.lineHeight + 15;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ([self.delegate respondsToSelector:@selector(textInputTableViewCellTextWillChange:)]) {
[self.delegate textInputTableViewCellTextWillChange:self];
}
return YES;
}
- (void)textViewDidChange:(UITextView *)textView {
if ([self.delegate respondsToSelector:@selector(textInputTableViewCellTextDidChange:)]) {
[self.delegate textInputTableViewCellTextDidChange:self];
}
}
Ensuite, nous l’utilisons dans TableViewController
@interface SomeTableViewController () <TextInputTableViewCellDelegate>
@end
@implementation SomeTableViewController
. . . . . . . . . . . . . . . . . . . .
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TextInputTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: TextInputTableViewCellIdentifier forIndexPath:indexPath];
cell.delegate = self;
cell.minLines = 3;
. . . . . . . . . .
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (void)textInputTableViewCellWillChange:(TextInputTableViewCell *)cell {
cell.lastRelativeFrameOriginY = cell.frame.Origin.y - self.tableView.contentOffset.y;
}
- (void)textInputTableViewCellTextDidChange:(TextInputTableViewCell *)cell {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[UIView performWithoutAnimation:^{
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:indexPath];
}];
CGFloat contentOffsetY = cell.frame.Origin.y - cell.lastRelativeFrameOriginY;
self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, contentOffsetY);
CGRect caretRect = [cell.textView caretRectForPosition:cell.textView.selectedTextRange.start];
caretRect = [self.tableView convertRect:caretRect fromView:cell.textView];
CGRect visibleRect = self.tableView.bounds;
visibleRect.Origin.y += self.tableView.contentInset.top;
visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
BOOL res = CGRectContainsRect(visibleRect, caretRect);
if (!res) {
caretRect.size.height += 5;
[self.tableView scrollRectToVisible:caretRect animated:NO];
}
}
@end
Ici, minLines
permet de définir la hauteur minimale de textView (pour résister à la minimisation de la hauteur par AutoLayout avec UITableViewAutomaticDimension).
moveRowAtIndexPath:indexPath:
avec le même chemin indexPath démarre le calcul et la mise en page de la hauteur de tableViewCell.
performWithoutAnimation:
supprime les effets secondaires (le décalage de contenu tableView saute au début d'une nouvelle ligne lors de la frappe).
Il est important de conserver relativeFrameOriginY
(et non contentOffsetY
!) Lors de la mise à jour des cellules car contentSize
des cellules avant que la cellule actuelle puisse être modifiée de manière inattendue par le calcul autoLayout. Il supprime les sauts visuels sur la césure du système lors de la frappe de mots longs.
Notez que vous ne devez pas définir la propriétéestimatedRowHeight
! Ce qui suit ne marche pas
self.tableView.estimatedRowHeight = UITableViewAutomaticDimension;
tilisez uniquement la méthode tableViewDelegate.
=============================================== =========================
Si cela ne vous gêne pas de faire une faible liaison entre tableView et tableViewCell et de mettre à jour la géométrie de la tableView depuis tableViewCell, il est possible de mettre à jour TextInputTableViewCell
classe ci-dessus:
@interface TextInputTableViewCell : UITableViewCell
@property (nonatomic, weak) id<TextInputTableViewCellDelegate> delegate;
@property (nonatomic, weak) UITableView *tableView;
@property (nonatomic, readonly) UITextView *textView;
@property (nonatomic) NSInteger minLines;
@end
#import "TextInputTableViewCell.h"
@interface TextInputTableViewCell () <UITextViewDelegate> {
NSLayoutConstraint *_heightConstraint;
CGFloat _lastRelativeFrameOriginY;
}
@property (nonatomic) UITextView *textView;
@end
@implementation TextInputTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
_textView = [UITextView new];
_textView.translatesAutoresizingMaskIntoConstraints = NO;
_textView.delegate = self;
_textView.scrollEnabled = NO;
_textView.font = CELL_REG_FONT;
_textView.textContainer.lineFragmentPadding = 0.0;
_textView.textContainerInset = UIEdgeInsetsZero;
[self.contentView addSubview:_textView];
[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
[self.contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" options:nil metrics:nil views:@{@"view": _textView}]];
_heightConstraint = [NSLayoutConstraint constraintWithItem: _textView
attribute: NSLayoutAttributeHeight
relatedBy: NSLayoutRelationGreaterThanOrEqual
toItem: nil
attribute: NSLayoutAttributeNotAnAttribute
multiplier: 0.0
constant: (_textView.font.lineHeight + 15)];
_heightConstraint.priority = UILayoutPriorityRequired - 1;
[_textView addConstraint:_heightConstraint];
}
return self;
}
- (void)prepareForReuse {
[super prepareForReuse];
self.minLines = 1;
self.tableView = nil;
}
- (void)setMinLines:(NSInteger)minLines {
_heightConstraint.constant = minLines * _textView.font.lineHeight + 15;
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
_lastRelativeFrameOriginY = self.frame.Origin.y - self.tableView.contentOffset.y;
return YES;
}
- (void)textViewDidChange:(UITextView *)textView {
NSIndexPath *indexPath = [self.tableView indexPathForCell:self];
if (indexPath == nil) return;
[UIView performWithoutAnimation:^{
[self.tableView moveRowAtIndexPath:indexPath toIndexPath:indexPath];
}];
CGFloat contentOffsetY = self.frame.Origin.y - _lastRelativeFrameOriginY;
self.tableView.contentOffset = CGPointMake(self.tableView.contentOffset.x, contentOffsetY);
CGRect caretRect = [self.textView caretRectForPosition:self.textView.selectedTextRange.start];
caretRect = [self.tableView convertRect:caretRect fromView:self.textView];
CGRect visibleRect = self.tableView.bounds;
visibleRect.Origin.y += self.tableView.contentInset.top;
visibleRect.size.height -= self.tableView.contentInset.top + self.tableView.contentInset.bottom;
BOOL res = CGRectContainsRect(visibleRect, caretRect);
if (!res) {
caretRect.size.height += 5;
[self.tableView scrollRectToVisible:caretRect animated:NO];
}
}
@end
La hauteur de votre cellule sera calculée en fonction du contenu de UILabel, mais tout le texte sera affiché par TextField.
Si vous souhaitez ajuster automatiquement la hauteur de UITableViewCell
en fonction de la hauteur de la hauteur intérieure de UITextView
. Voir ma réponse ici: https://stackoverflow.com/a/45890087/1245231
La solution est assez simple et devrait fonctionner depuis iOS 7. Assurez-vous que l'option Scrolling Enabled
est désactivée pour la UITextView
dans la UITableViewCell
du StoryBoard.
Ensuite, dans viewDidLoad () de votre UITableViewController, définissez les tableView.rowHeight = UITableViewAutomaticDimension
et tableView.estimatedRowHeight > 0
tels que:
override func viewDidLoad() {
super.viewDidLoad()
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 44.0
}
C'est ça. La hauteur de UITableViewCell
sera automatiquement ajustée en fonction de la hauteur intérieure de UITextView
.
Version rapide
func textViewHeightForAttributedText(text: NSAttributedString, andWidth width: CGFloat) -> CGFloat {
let calculationView = UITextView()
calculationView.attributedText = text
let size = calculationView.sizeThatFits(CGSize(width: width, height: CGFloat.max))
return size.height
}
UITextView *txtDescLandscape=[[UITextView alloc] initWithFrame:CGRectMake(2,20,310,2)];
txtDescLandscape.editable =NO;
txtDescLandscape.textAlignment =UITextAlignmentLeft;
[txtDescLandscape setFont:[UIFont fontWithName:@"ArialMT" size:15]];
txtDescLandscape.text =[objImage valueForKey:@"imgdescription"];
txtDescLandscape.text =[txtDescLandscape.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[txtDescLandscape sizeToFit];
[headerView addSubview:txtDescLandscape];
CGRect txtViewlandscpframe = txtDescLandscape.frame;
txtViewlandscpframe.size.height = txtDescLandscape.contentSize.height;
txtDescLandscape.frame = txtViewlandscpframe;
je pense que de cette façon, vous pouvez compter la hauteur de votre vue texte, puis redimensionner votre cellule en tant que table, en fonction de cette hauteur, afin que vous puissiez afficher le texte intégral sur une cellule.