Come dimensiono un UITextView in base al suo contenuto?
-
09-06-2019 - |
Domanda
Esiste un buon modo per regolare la dimensione di a UITextView
conformarsi al suo contenuto?Diciamo per esempio che ho a UITextView
che contiene una riga di testo:
"Hello world"
Quindi aggiungo un'altra riga di testo:
"Goodbye world"
Esiste un buon modo in Cocoa Touch per ottenere il file rect
che manterrà tutte le righe nella vista testo in modo da poter regolare di conseguenza la vista genitore?
Come altro esempio, guarda il campo delle note per gli eventi nell'applicazione Calendario: nota come la cella (e il file UITextView
contiene) si espande per contenere tutte le righe di testo nella stringa delle note.
Soluzione
Funziona sia per iOS 6.1 che per 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;
}
O in Swift (funziona con Swift 4.1 in 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)
Se desideri supporto per iOS 6.1 dovresti anche:
textview.scrollEnabled = NO;
Altri suggerimenti
Questo non funziona più su iOS 7 o versioni successive
In realtà esiste un modo molto semplice per ridimensionare il file UITextView
all'altezza corretta del contenuto.Può essere fatto utilizzando il UITextView
contentSize
.
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
Una cosa da notare è che è corretto contentSize
è disponibile solo Dopo IL UITextView
è stato aggiunto alla vista con addSubview
.Prima di ciò è uguale a frame.size
Questo non funzionerà se il layout automatico è attivo.Con il layout automatico, l'approccio generale consiste nell'utilizzare il file sizeThatFits
metodo e aggiornare il file constant
valore su un vincolo di altezza.
CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;
heightConstraint
è un vincolo di layout che in genere si imposta tramite un IBOutlet collegando la proprietà al vincolo di altezza creato in uno storyboard.
Solo per aggiungere a questa straordinaria risposta, 2014, se:
[self.textView sizeToFit];
c'è una differenza di comportamento con il iPhone6+ soltanto:
Solo con 6+ (non 5 o 6) aggiunge "un'altra riga vuota" a UITextView.La "soluzione RL" risolve questo problema perfettamente:
CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
Risolve il problema della "linea extra" su 6+.
Per effettuare un dimensionamento dinamico UITextView
all'interno di un UITableViewCell
, ho scoperto che la seguente combinazione funziona in Xcode 6 con l'SDK di iOS 8:
- Aggiungere un
UITextView
ad aUITableViewCell
e vincolarlo ai lati - Impostare il
UITextView
'SscrollEnabled
proprietà aNO
.Con lo scorrimento abilitato, il frame delUITextView
è indipendente dalla dimensione del contenuto, ma con lo scorrimento disabilitato esiste una relazione tra i due. Se la tua tabella utilizza l'altezza della riga predefinita originale di 44, calcolerà automaticamente l'altezza della riga, ma se hai modificato l'altezza della riga predefinita in qualcos'altro, potrebbe essere necessario attivare manualmente il calcolo automatico dell'altezza della riga in
viewDidLoad
:tableView.estimatedRowHeight = 150; tableView.rowHeight = UITableViewAutomaticDimension;
Per il dimensionamento dinamico di sola lettura UITextView
sì, questo è tutto.Se consenti agli utenti di modificare il testo nel tuo file UITextView
, devi anche:
Implementare il
textViewDidChange:
metodo delUITextViewDelegate
protocollo e informarlotableView
per ridipingersi ogni volta che il testo viene modificato:- (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; }
E non dimenticare di impostare il
UITextView
delegare da qualche parte, inStoryboard
o dentrotableView:cellForRowAtIndexPath:
Veloce:
textView.sizeToFit()
Nella mia (limitata) esperienza,
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
non rispetta i caratteri di fine riga, quindi potresti ritrovarti con caratteri molto più brevi CGSize
di quanto effettivamente richiesto.
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
sembra rispettare le nuove righe.
Inoltre, il testo non viene effettivamente visualizzato nella parte superiore del file UITextView
.Nel mio codice, ho impostato la nuova altezza del UITextView
essere 24 pixel più grande dell'altezza restituita dal file sizeOfFont
metodi.
In iOS6, puoi controllare il file contentSize
proprietà di UITextView subito dopo aver impostato il testo.In iOS7, questo non funzionerà più.Se desideri ripristinare questo comportamento per iOS7, inserisci il seguente codice in una sottoclasse di 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;
}
}
Pubblicherò la soluzione giusta in fondo alla pagina nel caso qualcuno sia coraggioso (o abbastanza disperato) da leggere fino a questo punto.
Ecco il repository gitHub per coloro che non vogliono leggere tutto quel testo: ridimensionabileTextView
Funziona con iOs7 (e credo che funzionerà con iOs8) e con il layout automatico.Non hai bisogno di numeri magici, disabilitare il layout e cose del genere. Soluzione breve ed elegante.
Penso che tutto il codice relativo ai vincoli dovrebbe andare a updateConstraints
metodo.Quindi, creiamone uno nostro ResizableTextView
.
Il primo problema che incontriamo qui è che non conosciamo prima la dimensione reale del contenuto viewDidLoad
metodo.Possiamo prendere una strada lunga e piena di bug e calcolarla in base alla dimensione del carattere, alle interruzioni di riga, ecc.Ma abbiamo bisogno di una soluzione solida, quindi faremo:
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];
Quindi ora conosciamo il contenuto reale, non importa dove siamo:prima o dopo viewDidLoad
.Ora aggiungi il vincolo di altezza su textView (tramite storyboard o codice, non importa come).Adegueremo quel valore con our contentSize.height
:
[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = contentSize.height;
*stop = YES;
}
}];
L'ultima cosa da fare è dire a superclass updateConstraints
.
[super updateConstraints];
Ora la nostra classe è simile a:
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];
}
Bello e pulito, vero?E non devi avere a che fare con quel codice nel tuo controllori!
Ma aspetta! E NESSUNA ANIMAZIONE!
Puoi facilmente animare le modifiche da apportare textView
allungare dolcemente.Ecco un esempio:
[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];
Hai provato [textView sizeThatFits:textView.bounds]
?
Modificare:sizeThatFits restituisce la dimensione ma non ridimensiona effettivamente il componente.Non sono sicuro se è quello che vuoi, o se [textView sizeToFit]
è più quello che stavi cercando.In entrambi i casi, non so se si adatterà perfettamente al contenuto che desideri, ma è la prima cosa da provare.
Un altro metodo è trovare la dimensione che occuperà una particolare stringa utilizzando il file NSString
metodo:
-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
Ciò restituisce la dimensione del rettangolo che si adatta alla stringa data con il carattere dato.Passa una dimensione con la larghezza desiderata e un'altezza massima, quindi puoi guardare l'altezza restituita per adattarla al testo.Esiste una versione che ti consente di specificare anche la modalità di interruzione di riga.
È quindi possibile utilizzare la dimensione restituita per modificare la dimensione della visualizzazione per adattarla.
Se non hai il UITextView
utile (ad esempio, stai ridimensionando le celle della vista tabella), dovrai calcolare la dimensione misurando la stringa, quindi tenendo conto degli 8 pt di riempimento su ciascun lato di a UITextView
.Ad esempio, se conosci la larghezza desiderata della visualizzazione del testo e desideri determinare l'altezza corrispondente:
NSString * string = ...;
CGFloat textViewWidth = ...;
UIFont * font = ...;
CGSize size = CGSizeMake(textViewWidth - 8 - 8, 100000);
size.height = [string sizeWithFont:font constrainedToSize:size].height + 8 + 8;
Qui, ogni 8 rappresenta uno dei quattro bordi imbottiti e 100000 serve solo come dimensione massima molto grande.
In pratica, potresti voler aggiungere un extra font.leading
all'altezza;questo aggiunge una riga vuota sotto il testo, che potrebbe apparire migliore se ci sono controlli visivamente pesanti direttamente sotto la visualizzazione del testo.
Possiamo farlo con dei vincoli.
2.Crea IBOutlet per quel vincolo di altezza.
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;
3. Non dimenticare di impostare il delegato per la tua visualizzazione testuale.
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;
}];
}
quindi aggiorna il tuo vincolo in questo modo :)
In combinazione con la risposta di Mike McMaster, potresti voler fare qualcosa del tipo:
[myTextView setDelegate: self];
...
- (void)textViewDidChange:(UITextView *)textView {
if (myTextView == textView) {
// it changed. Do resizing here.
}
}
Ho scoperto un modo per ridimensionare l'altezza di un campo di testo in base al testo al suo interno e anche disporre un'etichetta sotto di esso in base all'altezza del campo di testo!Ecco il codice.
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];
Ragazzi, usate il layout automatico e sizetofit non funziona, quindi controllate una volta il vincolo di larghezza.Se non hai rispettato il vincolo di larghezza, l'altezza sarà accurata.
Non è necessario utilizzare altre API.solo una riga risolverebbe tutto il problema.
[_textView sizeToFit];
Qui mi preoccupavo solo dell'altezza, mantenendo fissa la larghezza e non avevo rispettato il vincolo di larghezza del mio TextView nello storyboard.
E questo per mostrare il contenuto dinamico dei servizi.
Spero che questo possa aiutare..
A partire da iOS 8, è possibile utilizzare le funzionalità di layout automatico di un UITableView per ridimensionare automaticamente un UITextView senza alcun codice personalizzato.Ho inserito un progetto github che lo dimostra in azione, ma ecco la chiave:
- È necessario che lo scorrimento di UITextView sia disabilitato, cosa che puoi eseguire a livello di codice o tramite il generatore di interfacce.Non verrà ridimensionato se lo scorrimento è abilitato poiché lo scorrimento consente di visualizzare contenuti più grandi.
- In viewDidLoad per UITableViewController, è necessario impostare un valore per stimatoRowHeight e quindi impostare il valore
rowHeight
AUITableViewAutomaticDimension
.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = self.tableView.rowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- La destinazione di distribuzione del progetto deve essere iOS 8 o versione successiva.
Ha funzionato bene quando avevo bisogno di creare del testo in un file UITextView
adattarsi ad un'area specifica:
// 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); }
ecco la versione rapida di @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
Ho esaminato tutte le risposte e tutte mantengono la larghezza fissa e regolano solo l'altezza.Se desideri regolare anche la larghezza puoi utilizzare molto facilmente questo metodo:
quindi quando configuri la visualizzazione del testo, imposta lo scorrimento disabilitato
textView.isScrollEnabled = false
e poi nel metodo delegato func textViewDidChange(_ textView: UITextView)
aggiungi questo codice:
func textViewDidChange(_ textView: UITextView) {
let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
textView.frame = CGRect(origin: textView.frame.origin, size: newSize)
}
Uscite:
disabilitare lo scorrimento
aggiungere costanti
e aggiungi il tuo testo
[yourTextView setText:@"your text"];
[yourTextView layoutIfNeeded];
se usi UIScrollView
dovresti aggiungere anche questo;
[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;
}
Per iOS 7.0, invece di impostare il file frame.size.height
al contentSize.height
(che attualmente non fa nulla) use [textView sizeToFit]
.
Vedere questa domanda.
Spero che questo ti aiuti:
- (void)textViewDidChange:(UITextView *)textView {
CGSize textSize = textview.contentSize;
if (textSize != textView.frame.size)
textView.frame.size = textSize;
}
se arriva qualche altro, questa soluzione funziona per me, 1"Ronnie Liew"+4"user63934" (il mio testo arriva dal servizio web):notare i 1000 (niente può essere così grande "nel mio caso")
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;
E questo è...Saluti
Il modo migliore che ho scoperto per ridimensionare l'altezza di UITextView in base alla dimensione del testo.
CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX)];
oppure puoi USARE
CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX) lineBreakMode:NSLineBreakByTruncatingTail];
Per coloro che desiderano che la visualizzazione del testo si sposti effettivamente verso l'alto e mantenga la posizione della riga inferiore
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);
}
L'unico codice che funzionerà è quello che utilizza "SizeToFit" come nella risposta jhibberd sopra ma in realtà non funzionerà a meno che non lo chiami VisualizzaDidAppear o collegarlo all'evento modificato del testo UITextView.
Sulla base della risposta di Nikita Took sono arrivato alla seguente soluzione in Swift che funziona su iOS 8 con layout automatico:
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
}
}
}
Risposta rapida:Il codice seguente calcola l'altezza del tuo 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)))
Ora puoi impostare l'altezza del tuo textView su myTextHeight
Ecco la risposta se hai bisogno di ridimensionare textView
E tableViewCell
dinamicamente dentro staticTableView