Ich habe eine UITableView
Ausführung unter iOS 8 und verwende automatische Zellenhöhen aufgrund von Einschränkungen in einem Storyboard.
Eine meiner Zellen enthält eine einzelne UITextView
und ich muss sie basierend auf Benutzereingaben zusammenziehen und erweitern. Tippen Sie auf, um den Text zu verkleinern / erweitern.
Dazu füge ich der Textansicht eine Laufzeitbeschränkung hinzu und ändere die Konstante der Einschränkung als Reaktion auf Benutzerereignisse:
-(void)collapse:(BOOL)collapse; {
_collapsed = collapse;
if(collapse)
[_collapsedtextHeightConstraint setConstant: kCollapsedHeight]; // 70.0
else
[_collapsedtextHeightConstraint setConstant: [self idealCellHeightToShowFullText]];
[self setNeedsUpdateConstraints];
}
Wann immer ich dies tue, verpacke ich es in tableView
Updates und rufe an [tableView setNeedsUpdateConstraints]
:
[tableView beginUpdates];
[_briefCell collapse:!_showFullBriefText];
[tableView setNeedsUpdateConstraints];
// I have also tried
// [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
// with exactly the same results.
[tableView endUpdates];
Wenn ich das mache, wird meine Zelle zwar erweitert (und dabei animiert), aber ich erhalte eine Warnung zu Einschränkungen:
2014-07-31 13:29:51.792 OneFlatEarth[5505:730175] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSLayoutConstraint:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>",
"<NSLayoutConstraint:0x7f94dced2260 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...']-(15)-| (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",
"<NSLayoutConstraint:0x7f94dced2350 V:|-(6)-[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'] (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",
"<NSLayoutConstraint:0x7f94dced6480 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f94de5773a0(91)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>
388 ist meine berechnete Höhe, die anderen Einschränkungen für die UITextView
sind meine von Xcode / IB.
Das letzte stört mich - ich vermute, das UIView-Encapsulated-Layout-Height
ist die berechnete Höhe der Zelle, wenn sie zum ersten Mal gerendert wird - (ich setze meine UITextView
Höhe auf> = 70,0), aber es scheint nicht richtig, dass diese abgeleitete Einschränkung dann eine überschreibt Benutzer cnstraint aktualisiert.
Schlimmer noch, obwohl der Layoutcode besagt, dass versucht wird, meine Höhenbeschränkung zu brechen, ist dies nicht der Fall. Anschließend wird die Zellenhöhe neu berechnet und alles wird so gezeichnet, wie ich es möchte.
Also, was ist NSLayoutConstraint
UIView-Encapsulated-Layout-Height
(ich vermute, es ist die berechnete Höhe für die automatische Zellengröße) und wie sollte ich vorgehen, um es zu zwingen, sauber neu zu berechnen?
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
. Ich denke, dass das anfängliche Einstellen der Autoresize-Maske das Hinzufügen der letzten Einschränkung verhindert. Ich habe diese Lösung hier gefunden: github.com/wordpress-mobile/WordPress-iOS/commit/…<rect key="frame" x="0.0" y="0.0" width="600" height="110"/>
in ihrer Definition fehlte , was mich zu der Annahme führte, dass dies ein IB-Fehler ist . Zumindest meins war es sowieso.Antworten:
Versuchen Sie, die Priorität Ihres
_collapsedtextHeightConstraint
auf 999 zu senken. Auf diese Weise hat die vom System bereitgestellteUIView-Encapsulated-Layout-Height
Einschränkung immer Vorrang.Es basiert auf dem, was Sie zurückgeben
-tableView:heightForRowAtIndexPath:
. Stellen Sie sicher, dass Sie den richtigen Wert und Ihre eigene Einschränkung zurückgeben, und die generierte sollte identisch sein. Die niedrigere Priorität für Ihre eigene Einschränkung wird nur vorübergehend benötigt, um Konflikte zu verhindern, während Animationen zum Reduzieren / Erweitern ausgeführt werden.quelle
UIView-Encapsulated-Layout-Height
Einschränkung wird von UITableView hinzugefügt, sobald die Höhen bestimmt sind. Ich berechne die Höhe basierend auf dersystemLayoutSizeFittingSize
der Inhaltsansicht. Hier spielt dasUIView-Encapsulated-Layout-Height
keine Rolle. Dann setzt die tableView die contentSize explizit auf den von zurückgegebenen WertheightForRowAtIndexPath:
. In diesem Fall ist es richtig, die Priorität unserer benutzerdefinierten Einschränkungen zu verringern, da die tableView-Einschränkung nach der Berechnung der rowHeights Vorrang haben muss.UIView-Encapsulated-Layout-Height
es falsch ist, wenn ich die Priorität nicht absenke ...UIView-Encapsulated-Layout-Width
in meinem Fall hinzugefügte ist einfach falsch, aber es scheint meinen expliziten Einschränkungen zur Laufzeit vorzuziehen.Ich habe ein ähnliches Szenario: eine Tabellenansicht mit einer Zeilenzelle, in der sich einige Zeilen mit UILabel-Objekten befinden. Ich verwende iOS 8 und Autolayout.
Beim Drehen habe ich die falsche vom System berechnete Zeilenhöhe erhalten (43,5 ist viel geringer als die tatsächliche Höhe). Es sieht aus wie:
Es ist nicht nur eine Warnung. Das Layout meiner Tabellenansichtszelle ist schrecklich - der gesamte Text überlappt sich in einer Textzeile.
Es überrascht mich, dass die folgende Zeile mein Problem auf magische Weise "behebt" (Autolayout beschwert sich über nichts und ich bekomme, was ich auf dem Bildschirm erwarte):
mit oder ohne diese Zeile:
quelle
estimatedRowHeight
desto häufigercellForRowAtIndexPath
aufgerufen wird. Tabellenansichtshöhe geteilt durch geschätzte Zeilenhöhenzeiten, um genau zu sein. Auf einem 12-Zoll-iPad Pro kann dies möglicherweise eine Zahl von Tausenden sein, die Datenquelle hämmern und zu einer erheblichen Verzögerung führen.Ich konnte die Warnung zum Verschwinden bringen, indem ich eine Priorität für einen der Werte in der Einschränkung angab, die laut Warnmeldungen unterbrochen werden musste (siehe unten
"Will attempt to recover by breaking constraint"
). Es scheint, dass49
die Warnung verschwindet, solange ich die Priorität auf etwas Größeres als setze .Für mich bedeutete dies, meine Einschränkung zu ändern. Die Warnung besagte, dass versucht wurde zu brechen:
@"V:|[contentLabel]-[quoteeLabel]|"
zu:
@"V:|-0@500-[contentLabel]-[quoteeLabel]|"
Tatsächlich kann ich jedem Element dieser Einschränkung eine Priorität hinzufügen, und es wird funktionieren. Es scheint egal zu sein, welches. Meine Zellen haben die richtige Höhe und die Warnung wird nicht angezeigt. Roger, zum Beispiel, versuchen Sie,
@500
direkt nach der388
Höhenwertbeschränkung (z388@500
. B. ) hinzuzufügen .Ich bin mir nicht ganz sicher, warum das funktioniert, aber ich habe ein wenig nachgeforscht. In der NSLayoutPriority-Enumeration scheint die
NSLayoutPriorityFittingSizeCompression
Prioritätsstufe zu sein50
. Die Dokumentation für diese Prioritätsstufe lautet:Die Dokumentation für die referenzierte
fittingSize
Nachricht lautet:Ich habe nicht darüber hinaus gegraben, aber es scheint sinnvoll zu sein, dass dies etwas damit zu tun hat, wo das Problem liegt.
quelle
Ich war in der Lage , diesen Fehler zu beheben , indem ein falsches Entfernen ,
cell.layoutIfNeeded()
dass ich in meinem hattetableView
‚s -cellForRowAt
Methode.quelle
In 99,9% der Fälle
UITableViews
treten bei Verwendung benutzerdefinierter Zellen oder Header alle Konflikte auf, wenn die Tabelle beim ersten Mal geladen wird. Nach dem Laden wird der Konflikt normalerweise nicht mehr angezeigt.Dies liegt daran, dass die meisten Entwickler normalerweise eine feste Höhe oder eine Ankerbeschränkung verwenden, um ein Element in der Zelle / Kopfzeile zu gestalten. Der Konflikt tritt auf, weil beim
UITableView
ersten Laden / Auslegen die Höhe der Zellen auf 0 gesetzt wird. Dies steht offensichtlich im Widerspruch zu Ihren eigenen Einschränkungen. Um dies zu lösen, setzen Sie einfach alle festen Höhenbeschränkungen auf eine niedrigere Priorität (.defaultHigh
). Lesen Sie die Konsolenmeldung sorgfältig durch und sehen Sie, welche Einschränkung das Layoutsystem aufgehoben hat. Normalerweise muss die Priorität geändert werden. Sie können die Priorität folgendermaßen ändern:quelle
Versuchen Sie, die Zelle neu zu laden, anstatt die Tabellenansicht zu informieren, um ihre Einschränkungen zu aktualisieren:
UIView-Encapsulated-Layout-Height
ist wahrscheinlich die Höhe, die die Tabellenansicht für die Zelle während des anfänglichen Ladens berechnet hat, basierend auf den Einschränkungen der Zelle zu diesem Zeitpunkt.quelle
Andere Möglichkeit:
Wenn Sie das automatische Layout verwenden, um die Zellenhöhe zu berechnen (die Höhe von contentView, meistens wie unten), und wenn Sie ein geeignetes Ansichtstrennzeichen haben, müssen Sie die Trennzeichenhöhe hinzufügen, um zur Zellenhöhe zurückzukehren. Sobald Sie die richtige Höhe erreicht haben, wird diese Autolayout-Warnung nicht mehr angezeigt.
quelle
UITableViewAutomaticDimension
inheightForRowAtIndexPath
kehre ich[sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] + 0.1
[sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 0.1
Wie von Jesse in dem Kommentar der Frage erwähnt, funktioniert dies für mich:
Zu Ihrer Information, dieses Problem tritt in iOS 10 nicht auf.
quelle
Ich hatte diesen Fehler, als ich UITableViewAutomaticDimension verwendete und eine Höhenbeschränkung für eine Ansicht innerhalb der Zelle änderte.
Ich fand schließlich heraus, dass es daran lag, dass der Wert der Einschränkungskonstante nicht auf die nächste ganze Zahl aufgerundet wurde.
quelle
Durch die Größenanpassung der Textansicht an den Inhalt und die Aktualisierung der Höhenbeschränkungskonstante auf die resultierende Höhe wurde der
UIView-Encapsulated-Layout-Height
Einschränkungskonflikt für mich behoben , z.quelle
Nachdem ich einige Stunden damit verbracht hatte, mir mit diesem Fehler den Kopf zu kratzen, fand ich endlich eine Lösung, die für mich funktionierte. Mein Hauptproblem war, dass ich mehrere Schreibfedern für verschiedene Zelltypen registriert hatte, aber ein Zelltyp speziell unterschiedliche Größen haben durfte (nicht alle Instanzen dieser Zelle werden dieselbe Größe haben). Das Problem trat also auf, als die Tabellenansicht versuchte, eine Zelle dieses Typs aus der Warteschlange zu entfernen, und sie zufällig eine andere Höhe hatte. Ich habe es durch Einstellen gelöst
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; self.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
wann immer die Zelle ihre Daten hatte, um ihre Größe zu berechnen. Ich denke, es kann sein
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
etwas wie
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; cell.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});
Hoffe das hilft!
quelle
TableView ruft die Höhe für die Zelle bei indexPath vom Delegaten ab. Dann holen Sie sich die Zelle von
cellForRowAtIndexPath
:wenn cell.contentView.height: 0 // <-> (UIView-Encapsulated-Layout-Höhe: 0 @ 1000) top (10 @ 1000) in Konflikt mit (UIView-Encapsulated-Layout-Höhe: 0 @ 1000),
weil sie Prioritäten gleich 1000 sind. Wir müssen die höchste Priorität unter
UIView-Encapsulated-Layout-Height
der Priorität setzen.quelle
Ich bekam eine Nachricht wie diese:
Ich benutze einen Brauch
UITableViewCell
mitUITableViewAutomaticDimension
für die Höhe. Und ich habe auch dieestimatedHeightForRowAtIndex:
Methode implementiert .Die Einschränkung, die mir Probleme bereitete, sah ungefähr so aus
Wenn Sie die Einschränkung in diese ändern, wird das Problem behoben, aber wie bei einer anderen Antwort war ich der Meinung, dass dies nicht korrekt ist, da dies die Priorität einer Einschränkung senkt, die ich benötigen möchte:
Was mir jedoch aufgefallen ist, ist, dass dies auch funktioniert, wenn ich nur die Priorität entferne, und ich nicht die Protokolle für brechende Einschränkungen erhalte:
Dies ist ein bisschen rätselhaft, was der Unterschied zwischen
|-6-[title]-6-|
und ist|-[title-|
. Die Angabe der Größe ist für mich jedoch kein Problem, und die Protokolle werden entfernt, und ich muss die Priorität meiner erforderlichen Einschränkungen nicht verringern.quelle
Ich hatte ein ähnliches Problem mit einer Sammlungsansichtszelle.
Ich habe es gelöst, indem ich die Priorität der letzten Einschränkung, die mit dem unteren Rand der Zelle verknüpft war (die letzte in der Kette von oben nach unten in der Ansicht - dies bestimmt letztendlich ihre Höhe), auf 999 gesenkt habe.
Die Höhe der Zelle war korrekt und die Warnungen gingen weg.
quelle
Stellen Sie dies ein,
view.translatesAutoresizingMaskIntoConstraints = NO;
um dieses Problem zu beheben.quelle