Wie passe ich die Größe einer UITextView an ihren Inhalt an?
-
09-06-2019 - |
Frage
Gibt es eine gute Möglichkeit, die Größe von a anzupassen? UITextView
seinem Inhalt entsprechen?Sagen wir zum Beispiel, ich habe eine UITextView
das eine Textzeile enthält:
"Hello world"
Anschließend füge ich eine weitere Textzeile hinzu:
"Goodbye world"
Gibt es in Cocoa Touch eine gute Möglichkeit, das zu bekommen? rect
das alle Zeilen in der Textansicht enthält, sodass ich die übergeordnete Ansicht entsprechend anpassen kann?
Schauen Sie sich als weiteres Beispiel das Notizenfeld für Ereignisse in der Kalenderanwendung an – beachten Sie, wie die Zelle (und die UITextView
es enthält) wird erweitert, um alle Textzeilen in der Notizzeichenfolge aufzunehmen.
Lösung
Dies funktioniert sowohl für iOS 6.1 als auch für 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;
}
Oder in Swift (Funktioniert mit 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)
Wenn Sie Unterstützung für iOS 6.1 wünschen, sollten Sie außerdem:
textview.scrollEnabled = NO;
Andere Tipps
Dies funktioniert nicht mehr unter iOS 7 oder höher
Es gibt tatsächlich eine sehr einfache Möglichkeit, die Größe zu ändern UITextView
auf die richtige Höhe des Inhalts.Dies kann mit der erfolgen UITextView
contentSize
.
CGRect frame = _textView.frame;
frame.size.height = _textView.contentSize.height;
_textView.frame = frame;
Zu beachten ist, dass es richtig ist contentSize
ist nur verfügbar nach Die UITextView
wurde der Ansicht mit hinzugefügt addSubview
.Davor ist es gleich frame.size
Dies funktioniert nicht, wenn das automatische Layout aktiviert ist.Beim automatischen Layout besteht der allgemeine Ansatz darin, das zu verwenden sizeThatFits
Methode und aktualisieren Sie die constant
Wert für eine Höhenbeschränkung.
CGSize sizeThatShouldFitTheContent = [_textView sizeThatFits:_textView.frame.size];
heightConstraint.constant = sizeThatShouldFitTheContent.height;
heightConstraint
ist eine Layoutbeschränkung, die Sie normalerweise über ein IBOutlet einrichten, indem Sie die Eigenschaft mit der in einem Storyboard erstellten Höhenbeschränkung verknüpfen.
Nur um diese erstaunliche Antwort aus dem Jahr 2014 zu ergänzen, wenn Sie:
[self.textView sizeToFit];
Es gibt einen Unterschied im Verhalten mit dem iPhone6+ nur:
Nur bei 6+ (nicht bei 5s oder 6) wird der UITextView „eine weitere Leerzeile“ hinzugefügt.Die „RL-Lösung“ behebt dieses Problem perfekt:
CGRect _f = self.mainPostText.frame;
_f.size.height = self.mainPostText.contentSize.height;
self.mainPostText.frame = _f;
Es behebt das Problem der „zusätzlichen Zeile“ auf 6+.
Um eine dynamische Dimensionierung vorzunehmen UITextView
in einem UITableViewCell
, Ich habe festgestellt, dass die folgende Kombination in Xcode 6 mit dem iOS 8 SDK funktioniert:
- Füge hinzu ein
UITextView
zu einemUITableViewCell
und beschränke es auf die Seiten - Stellen Sie die ein
UITextView
'SscrollEnabled
Eigentum zuNO
.Wenn das Scrollen aktiviert ist, wird der Rahmen desUITextView
ist unabhängig von der Inhaltsgröße, aber wenn das Scrollen deaktiviert ist, besteht eine Beziehung zwischen beiden. Wenn Ihre Tabelle die ursprüngliche Standardzeilenhöhe von 44 verwendet, werden die Zeilenhöhen automatisch berechnet. Wenn Sie jedoch die Standardzeilenhöhe auf etwas anderes geändert haben, müssen Sie möglicherweise die automatische Berechnung der Zeilenhöhen manuell aktivieren
viewDidLoad
:tableView.estimatedRowHeight = 150; tableView.rowHeight = UITableViewAutomaticDimension;
Für schreibgeschützte dynamische Größenanpassung UITextView
s, das ist es.Wenn Sie Benutzern erlauben, den Text in Ihrem zu bearbeiten UITextView
, müssen Sie außerdem:
Implementieren Sie die
textViewDidChange:
Methode derUITextViewDelegate
Protokoll, und sagen Sie es demtableView
um sich jedes Mal neu zu zeichnen, wenn der Text bearbeitet wird:- (void)textViewDidChange:(UITextView *)textView; { [tableView beginUpdates]; [tableView endUpdates]; }
Und vergessen Sie nicht, das einzustellen
UITextView
irgendwohin delegieren, entweder hineinStoryboard
oder intableView:cellForRowAtIndexPath:
Schnell:
textView.sizeToFit()
Nach meiner (begrenzten) Erfahrung
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
respektiert keine Zeilenumbrüche, daher kann es sein, dass Sie am Ende viel kürzere Zeichen erhalten CGSize
als tatsächlich erforderlich ist.
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
scheint die Zeilenumbrüche zu respektieren.
Außerdem wird der Text oben nicht wirklich gerendert UITextView
.In meinem Code habe ich die neue Höhe des festgelegt UITextView
24 Pixel größer sein als die von zurückgegebene Höhe sizeOfFont
Methoden.
In iOS6 können Sie das überprüfen contentSize
Eigenschaft von UITextView, direkt nachdem Sie den Text festgelegt haben.Unter iOS7 wird dies nicht mehr funktionieren.Wenn Sie dieses Verhalten für iOS7 wiederherstellen möchten, platzieren Sie den folgenden Code in einer Unterklasse von 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;
}
}
Ich werde die richtige Lösung unten auf der Seite veröffentlichen, falls jemand mutig (oder verzweifelt genug) ist, bis zu diesem Punkt zu lesen.
Hier ist das GitHub-Repo für diejenigen, die nicht den ganzen Text lesen möchten: resizableTextView
Dies funktioniert mit iOS7 (und ich glaube, dass es auch mit iOS8 funktionieren wird) und mit Autolayout.Sie brauchen keine magischen Zahlen, deaktivieren das Layout und ähnliches. Kurze und elegante Lösung.
Ich denke, dass der gesamte einschränkungsbezogene Code an gehen sollte updateConstraints
Methode.Also machen wir unser eigenes ResizableTextView
.
Das erste Problem, auf das wir hier stoßen, besteht darin, dass wir die tatsächliche Inhaltsgröße vorher nicht kennen viewDidLoad
Methode.Wir können einen langen und fehlerhaften Weg gehen und ihn anhand der Schriftgröße, der Zeilenumbrüche usw. berechnen.Aber wir brauchen eine robuste Lösung, also machen wir:
CGSize contentSize = [self sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)];
Jetzt kennen wir also die tatsächliche Inhaltsgröße, egal wo wir sind:vorher oder nachher viewDidLoad
.Fügen Sie nun eine Höhenbeschränkung für textView hinzu (per Storyboard oder Code, egal wie).Wir werden diesen Wert mit unserem anpassen contentSize.height
:
[self.constraints enumerateObjectsUsingBlock:^(NSLayoutConstraint *constraint, NSUInteger idx, BOOL *stop) {
if (constraint.firstAttribute == NSLayoutAttributeHeight) {
constraint.constant = contentSize.height;
*stop = YES;
}
}];
Das Letzte, was Sie tun müssen, ist, Superclass dazu aufzufordern updateConstraints
.
[super updateConstraints];
Jetzt sieht unsere Klasse so aus:
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];
}
Hübsch und sauber, oder?Und Sie müssen sich nicht mit diesem Code befassen Controller!
Aber warte! Y KEINE ANIMATION!
Sie können Änderungen ganz einfach animieren, um sie vorzunehmen textView
sanft dehnen.Hier ist ein Beispiel:
[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];
Hast du versucht [textView sizeThatFits:textView.bounds]
?
Bearbeiten:sizeThatFits gibt die Größe zurück, ändert jedoch nicht die Größe der Komponente.Ich bin mir nicht sicher, ob Sie das wollen oder nicht [textView sizeToFit]
ist mehr das, was Sie gesucht haben.In beiden Fällen weiß ich nicht, ob es perfekt zu dem von Ihnen gewünschten Inhalt passt, aber es ist das Erste, was Sie ausprobieren sollten.
Eine andere Methode besteht darin, mithilfe von die Größe zu ermitteln, die eine bestimmte Zeichenfolge einnimmt NSString
Methode:
-(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size
Dies gibt die Größe des Rechtecks zurück, das zur angegebenen Zeichenfolge mit der angegebenen Schriftart passt.Übergeben Sie eine Größe mit der gewünschten Breite und einer maximalen Höhe, und dann können Sie sich die zurückgegebene Höhe ansehen, um sie an den Text anzupassen.Es gibt eine Version, mit der Sie auch den Zeilenumbruchmodus festlegen können.
Anschließend können Sie die zurückgegebene Größe verwenden, um die Größe Ihrer Ansicht anzupassen.
Wenn Sie das nicht haben UITextView
Praktisch (zum Beispiel, wenn Sie die Größe von Zellen in Tabellenansichten anpassen), müssen Sie die Größe berechnen, indem Sie die Zeichenfolge messen und dann die 8 Punkte Abstand auf jeder Seite von a berücksichtigen UITextView
.Wenn Sie beispielsweise die gewünschte Breite Ihrer Textansicht kennen und die entsprechende Höhe ermitteln möchten:
NSString * string = ...;
CGFloat textViewWidth = ...;
UIFont * font = ...;
CGSize size = CGSizeMake(textViewWidth - 8 - 8, 100000);
size.height = [string sizeWithFont:font constrainedToSize:size].height + 8 + 8;
Hier stellt jede 8 eine der vier gepolsterten Kanten dar und 100.000 dient lediglich als sehr große Maximalgröße.
In der Praxis möchten Sie möglicherweise ein Extra hinzufügen font.leading
zur Höhe;Dadurch wird eine Leerzeile unter Ihrem Text hinzugefügt, die möglicherweise besser aussieht, wenn direkt unter der Textansicht visuell umfangreiche Steuerelemente vorhanden sind.
Wir können es durch Einschränkungen tun.
2.Erstellen Sie IBOutlet für diese Höhenbeschränkung.
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *txtheightconstraints;
3. Vergessen Sie nicht, einen Delegaten für Ihre Textansicht festzulegen.
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;
}];
}
dann aktualisiere deine Einschränkung so :)
In Kombination mit der Antwort von Mike McMaster möchten Sie vielleicht etwas tun wie:
[myTextView setDelegate: self];
...
- (void)textViewDidChange:(UITextView *)textView {
if (myTextView == textView) {
// it changed. Do resizing here.
}
}
Ich habe eine Möglichkeit gefunden, die Höhe eines Textfelds entsprechend dem darin enthaltenen Text zu ändern und außerdem eine Beschriftung darunter basierend auf der Höhe des Textfelds anzuordnen!Hier ist der 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];
Leute, die Autolayout verwenden und eure Größe nicht funktioniert, dann überprüft bitte einmal eure Breitenbeschränkung.Wenn Sie die Breitenbeschränkung übersehen haben, ist die Höhe korrekt.
Es ist nicht erforderlich, eine andere API zu verwenden.Nur eine Zeile würde das gesamte Problem beheben.
[_textView sizeToFit];
Hier ging es mir nur um die Höhe und die Beibehaltung der Breite, und ich hatte die Breitenbeschränkung meiner Textansicht im Storyboard übersehen.
Und dies diente dazu, die dynamischen Inhalte der Dienste anzuzeigen.
Hoffe das könnte helfen..
Ab iOS 8 ist es möglich, die automatischen Layoutfunktionen einer UITableView zu verwenden, um die Größe einer UITextView automatisch und ohne benutzerdefinierten Code zu ändern.Ich habe ein Projekt eingefügt Github Das zeigt dies in Aktion, aber hier ist der Schlüssel:
- Für die UITextView muss das Scrollen deaktiviert sein, was Sie programmgesteuert oder über den Interface Builder tun können.Die Größe wird nicht geändert, wenn das Scrollen aktiviert ist, da Sie durch Scrollen den größeren Inhalt anzeigen können.
- In viewDidLoad für den UITableViewController müssen Sie einen Wert für geschätzteRowHeight festlegen und dann festlegen
rowHeight
ZuUITableViewAutomaticDimension
.
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.estimatedRowHeight = self.tableView.rowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
- Das Ziel der Projektbereitstellung muss iOS 8 oder höher sein.
Das funktionierte gut, als ich Text in einem erstellen musste UITextView
in einen bestimmten Bereich passen:
// 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); }
Hier ist die schnelle Version von @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
Ich habe alle Antworten überprüft und alle behalten die feste Breite bei und passen nur die Höhe an.Wenn Sie auch die Breite anpassen möchten, können Sie ganz einfach diese Methode verwenden:
Stellen Sie beim Konfigurieren Ihrer Textansicht daher sicher, dass das Scrollen deaktiviert ist
textView.isScrollEnabled = false
und dann in der Delegate-Methode func textViewDidChange(_ textView: UITextView)
füge diesen Code hinzu:
func textViewDidChange(_ textView: UITextView) {
let newSize = textView.sizeThatFits(CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude))
textView.frame = CGRect(origin: textView.frame.origin, size: newSize)
}
Ausgänge:
Scrollen deaktivieren
Fügen Sie Einschränkungen hinzu
und fügen Sie Ihren Text hinzu
[yourTextView setText:@"your text"];
[yourTextView layoutIfNeeded];
wenn du benutzt UIScrollView
Sie sollten dies auch hinzufügen;
[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;
}
Für iOS 7.0, anstatt das festzulegen frame.size.height
zum contentSize.height
(was derzeit nichts bewirkt) verwenden [textView sizeToFit]
.
Sehen diese Frage.
Hoffe das hilft:
- (void)textViewDidChange:(UITextView *)textView {
CGSize textSize = textview.contentSize;
if (textSize != textView.frame.size)
textView.frame.size = textSize;
}
Wenn jemand anderes hierher kommt, funktioniert diese Lösung für mich, 1"Ronnie Liew"+4"user63934" (Mein Text kommt vom Webdienst):Beachten Sie die 1000 (nichts kann „in meinem Fall“ so groß sein)
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;
Und das ist...Prost
Der beste Weg, den ich herausgefunden habe, ist, die Höhe der UITextView entsprechend der Textgröße anzupassen.
CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX)];
oder Sie können BENUTZEN
CGSize textViewSize = [YOURTEXTVIEW.text sizeWithFont:[UIFont fontWithName:@"SAMPLE_FONT" size:14.0]
constrainedToSize:CGSizeMake(YOURTEXTVIEW.frame.size.width, FLT_MAX) lineBreakMode:NSLineBreakByTruncatingTail];
Für diejenigen, die möchten, dass die Textansicht tatsächlich nach oben wandert und die Endposition beibehält
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);
}
Der einzige Code, der funktionieren wird, ist derjenige, der „SizeToFit“ wie in der obigen jhibberd-Antwort verwendet, aber tatsächlich wird er nicht aktiviert, es sei denn, Sie rufen ihn auf ViewDidAppear oder verbinden Sie es mit dem UITextView-Textänderungsereignis.
Basierend auf der Antwort von Nikita Took bin ich in Swift auf die folgende Lösung gekommen, die unter iOS 8 mit Autolayout funktioniert:
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
}
}
}
Schnelle Antwort:Der folgende Code berechnet die Höhe Ihrer Textansicht.
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)))
Jetzt können Sie die Höhe Ihrer Textansicht auf festlegen myTextHeight
Hier ist die Antwort, wenn Sie die Größe ändern müssen textView
Und tableViewCell
dynamisch in staticTableView