Ich habe meine benutzerdefinierte Zelle in IB entworfen, sie in Unterklassen unterteilt und meine Verkaufsstellen mit meiner benutzerdefinierten Klasse verbunden. Ich habe drei Unteransichten im Zellinhalt: UIView (cdView) und zwei Labels (titleLabel und emailLabel). Abhängig von den für jede Zeile verfügbaren Daten möchte ich manchmal UIView und zwei Beschriftungen in meiner Zelle und manchmal nur zwei Beschriftungen anzeigen lassen. Was ich versuche zu tun, ist das Festlegen von Einschränkungen auf diese Weise, wenn ich die UIView-Eigenschaft auf "hidden" setze oder sie aus dem Überblick entferne. Die beiden Labels werden nach links verschoben. Ich habe versucht, UIView als führende Einschränkung auf Superview (Zelleninhalt) für 10px und UILabels führende Einschränkungen für 10 px für die nächste Ansicht (UIView) festzulegen. Später in meinem Code
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(IndexPath *)indexPath {
...
Record *record = [self.records objectAtIndex:indexPath.row];
if ([record.imageURL is equalToString:@""]) {
cell.cdView.hidden = YES;
}
Ich verstecke meine cell.cdView und möchte, dass die Beschriftungen nach links verschoben werden, obwohl sie sich in derselben Position in Cell befinden. Ich habe versucht, cell.cdView aus dem Superview zu entfernen, aber es hat auch nicht funktioniert. Ich habe ein Bild beigefügt, um zu erklären, worum es mir geht.
Ich weiß, wie man das programmgesteuert macht und suche nicht nach dieser Lösung. Was ich möchte, ist das Festlegen von Einschränkungen in IB und ich erwarte, dass meine Unteransichten dynamisch verschoben werden, wenn andere Ansichten entfernt oder ausgeblendet werden. Kann man dies in IB mit automatischem Layout machen?
.....
Es ist möglich, aber Sie müssen etwas mehr Arbeit leisten. Es gibt ein paar konzeptionelle Dinge, die Sie zuerst aus dem Weg räumen können:
In Ihrem Fall bedeutet dies wahrscheinlich:
Was Sie tun müssen, ist vernünftigerweise over-constrain Ihre Etiketten. Lassen Sie Ihre vorhandenen Einschränkungen (10 Pkt. Abstand zur anderen Ansicht) allein, fügen Sie jedoch eine weitere Einschränkung hinzu: Legen Sie die linken Ränder der Beschriftungen 10 Pts vom linken Rand des Superviews entfernt mit einer nicht erforderlichen Priorität fest (die standardmäßige hohe Priorität funktioniert wahrscheinlich gut).
Wenn Sie möchten, dass sie sich nach links bewegen, entfernen Sie die linke Ansicht insgesamt. Die verbindliche 10-Punkt-Einschränkung für die linke Ansicht verschwindet zusammen mit der Ansicht, auf die sie sich bezieht, und es bleibt nur eine Einschränkung mit hoher Priorität, dass die Beschriftungen 10 Punkte von ihrem Superview entfernt sind. Beim nächsten Layout-Durchlauf sollten sie dann nach links erweitert werden, bis sie die Breite der Überblendung ausfüllen, jedoch nicht für Ihren Abstand um die Kanten.
Eine wichtige Einschränkung: Wenn Sie Ihre linke Ansicht immer wieder im Bild haben möchten, müssen Sie sie nicht nur wieder in die Ansichtshierarchie einfügen, sondern Sie müssen auch alle Einschränkungen wieder herstellen gleichzeitig erstellen. Dies bedeutet, dass Sie einen Weg benötigen, um die 10pt-Abstandsbeschränkung zwischen der Ansicht und ihren Beschriftungen wieder herzustellen, wenn diese Ansicht erneut angezeigt wird.
Das Hinzufügen oder Entfernen von Einschränkungen während der Laufzeit ist ein schwerer Vorgang, der die Leistung beeinträchtigen kann. Es gibt jedoch eine einfachere Alternative.
Richten Sie für die Ansicht, die Sie ausblenden möchten, eine Breitenbeschränkung ein. Beschränken Sie die anderen Ansichten mit einer führenden horizontalen Lücke auf diese Ansicht.
Aktualisieren Sie zum Ausblenden den .constant
der Breitenbeschränkung auf 0.f. Die anderen Ansichten bewegen sich automatisch nach links, um die Position einzunehmen.
Sehen Sie meine andere Antwort hier für weitere Details:
Wie kann ich Labelbeschränkungen während der Laufzeit ändern?
Für diejenigen, die nur iOS 8+ unterstützen, gibt es eine neue boolesche Eigenschaft active . Es wird helfen, nur erforderliche Einschränkungen dynamisch zu aktivieren
P.S. Constraint-Auslass muss strong sein, nicht schwach
Beispiel:
@IBOutlet weak var optionalView: UIView!
@IBOutlet var viewIsVisibleConstraint: NSLayoutConstraint!
@IBOutlet var viewIsHiddenConstraint: NSLayoutConstraint!
func showView() {
optionalView.isHidden = false
viewIsVisibleConstraint.isActive = true
viewIsHiddenConstraint.isActive = false
}
func hideView() {
optionalView.isHidden = true
viewIsVisibleConstraint.isActive = false
viewIsHiddenConstraint.isActive = true
}
Um einen Fehler im Storyboard zu beheben, müssen Sie das Kontrollkästchen Installed
für eine dieser Einschränkungen deaktivieren.
UIStackView (iOS 9+)
Eine weitere Option besteht darin, Ihre Ansichten in UIStackView
einzuhüllen. Sobald die Ansicht ausgeblendet ist, wird UIStackView
das Layout automatisch aktualisieren
UIStackView
positioniert seine Ansichten automatisch neu, wenn die hidden
-Eigenschaft in einer ihrer Unteransichten geändert wird (iOS 9+).
UIView.animateWithDuration(1.0) { () -> Void in
self.mySubview.hidden = !self.mySubview.hidden
}
Gehe zu 11:48 in diesem WWDC-Video für eine Demo:
Mein Projekt verwendet eine benutzerdefinierte @IBDesignable
-Unterklasse von UILabel
(um Konsistenz in Farbe, Schriftart, Einfügungen usw. zu gewährleisten), und ich habe Folgendes implementiert:
override func intrinsicContentSize() -> CGSize {
if hidden {
return CGSizeZero
} else {
return super.intrinsicContentSize()
}
}
Dadurch kann die Label-Unterklasse am automatischen Layout teilnehmen, nimmt jedoch keinen Platz ein, wenn sie ausgeblendet ist.
Für die Googlers: Aufbauend auf Max 'Antwort: Um das Problem der Polsterung zu lösen, das viele bemerkt haben, habe ich einfach die Höhe des Etiketts erhöht und diese Höhe als Trennzeichen anstelle der eigentlichen Polsterung verwendet. Diese Idee kann für jedes Szenario mit Ansichten erweitert werden.
Hier ist ein einfaches Beispiel:
In diesem Fall ordne ich die Höhe des Author - Labels einer geeigneten IBOutlet
zu:
@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;
und wenn ich die Höhe der Beschränkung auf 0.0f
setze, behalten wir die "Auffüllung" bei, da die Höhe der Play - Schaltfläche dies zulässt.
Am Ende habe ich 2 Xibs erstellt. Eine mit der linken Ansicht und eine ohne. Ich habe beide im Controller registriert und dann entschieden, welche Elemente während cellForRowAtIndexPath verwendet werden sollen.
Sie verwenden dieselbe UITableViewCell-Klasse. Der Nachteil ist, dass der Inhalt zwischen den Xibs doppelt vorhanden ist, aber diese Zellen sind ziemlich einfach. Der Vorteil ist, dass ich nicht über eine Menge Code verfügt, um manuell das Entfernen von Ansichten, das Aktualisieren von Einschränkungen usw. zu verwalten.
Im Allgemeinen ist dies wahrscheinlich eine bessere Lösung, da sie technisch unterschiedliche Layouts haben und daher unterschiedliche Xibs aufweisen sollten.
[self.table registerNib:[UINib nibWithNibName:@"TrackCell" bundle:nil] forCellReuseIdentifier:@"TrackCell"];
[self.table registerNib:[UINib nibWithNibName:@"TrackCellNoImage" bundle:nil] forCellReuseIdentifier:@"TrackCellNoImage"];
TrackCell *cell = [tableView dequeueReusableCellWithIdentifier:(appDelegate.showImages ? @"TrackCell" : @"TrackCellNoImage") forIndexPath:indexPath];
verbinden Sie die Einschränkung zwischen uiview und den Bezeichnungen als IBOutlet und setzen Sie das Prioritätsmitglied auf einen niedrigeren Wert, wenn hidden = YES eingestellt ist
In diesem Fall ordne ich die Höhe des Author-Labels einem entsprechenden IBOutlet zu:
@property (retain, nonatomic) IBOutlet NSLayoutConstraint* authorLabelHeight;
und wenn ich die Höhe der Beschränkung auf 0,0f setze, behalten wir die "Auffüllung" bei, da die Höhe des Play-Buttons dies erlaubt.
cell.authorLabelHeight.constant = 0;
Verwenden Sie zwei UIStackView-Funktionen Horizontal und Vertikal. Wenn einige Unteransichten des Stapels ausgeblendet sind und andere Stapelunteransichten verschoben werden, verwenden Sie Verteilung -> Proportional füllen für den vertikalen Stapel mit zwei UILabels und müssen für die erste UIView feste Breiten- und Höhenkonstanten festlegen
Versuchen Sie dies, ich habe folgenden Code implementiert,
Ich habe eine Ansicht auf ViewController, in der weitere drei Ansichten hinzugefügt wurden. Wenn eine Ansicht ausgeblendet wird, werden sich die anderen beiden Ansichten verschieben.
1.ViewController.h Datei
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet UIView *viewOne;
@property (strong, nonatomic) IBOutlet UIView *viewTwo;
@property (strong, nonatomic) IBOutlet UIView *viewThree;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewOneWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewTwoWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewThreeWidth;
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *viewBottomWidth;
@end
2.ViewController.m
#import "ViewController.h"
@interface ViewController ()
{
CGFloat viewOneWidthConstant;
CGFloat viewTwoWidthConstant;
CGFloat viewThreeWidthConstant;
CGFloat viewBottomWidthConstant;
}
@end
@implementation ViewController
@synthesize viewOne, viewTwo, viewThree;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a
nib.
/*
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
*/
// [viewOne setHidden:NO];
// [viewTwo setHidden:NO];
// [viewThree setHidden:NO];
// [viewOne setHidden:NO];
// [viewTwo setHidden:NO];
// [viewThree setHidden:YES];
// [viewOne setHidden:NO];
// [viewTwo setHidden:YES];
// [viewThree setHidden:NO];
// [viewOne setHidden:NO];
// [viewTwo setHidden:YES];
// [viewThree setHidden:YES];
// [viewOne setHidden:YES];
// [viewTwo setHidden:NO];
// [viewThree setHidden:NO];
// [viewOne setHidden:YES];
// [viewTwo setHidden:NO];
// [viewThree setHidden:YES];
// [viewOne setHidden:YES];
// [viewTwo setHidden:YES];
// [viewThree setHidden:NO];
// [viewOne setHidden:YES];
// [viewTwo setHidden:YES];
// [viewThree setHidden:YES];
[self hideShowBottomBar];
}
- (void)hideShowBottomBar
{
BOOL isOne = !viewOne.isHidden;
BOOL isTwo = !viewTwo.isHidden;
BOOL isThree = !viewThree.isHidden;
viewOneWidthConstant = _viewOneWidth.constant;
viewTwoWidthConstant = _viewTwoWidth.constant;
viewThreeWidthConstant = _viewThreeWidth.constant;
viewBottomWidthConstant = _viewBottomWidth.constant;
if (isOne && isTwo && isThree) {
// 0 0 0
_viewOneWidth.constant = viewBottomWidthConstant / 3;
_viewTwoWidth.constant = viewBottomWidthConstant / 3;
_viewThreeWidth.constant = viewBottomWidthConstant / 3;
}
else if (isOne && isTwo && !isThree) {
// 0 0 1
_viewOneWidth.constant = viewBottomWidthConstant / 2;
_viewTwoWidth.constant = viewBottomWidthConstant / 2;
_viewThreeWidth.constant = 0;
}
else if (isOne && !isTwo && isThree) {
// 0 1 0
_viewOneWidth.constant = viewBottomWidthConstant / 2;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = viewBottomWidthConstant / 2;
}
else if (isOne && !isTwo && !isThree) {
// 0 1 1
_viewOneWidth.constant = viewBottomWidthConstant;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = 0;
}
else if (!isOne && isTwo && isThree) {
// 1 0 0
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = viewBottomWidthConstant / 2;
_viewThreeWidth.constant = viewBottomWidthConstant / 2;
}
else if (!isOne && isTwo && !isThree) {
// 1 0 1
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = viewBottomWidthConstant;
_viewThreeWidth.constant = 0;
}
else if (!isOne && !isTwo && isThree) {
// 1 1 0
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = viewBottomWidthConstant;
}
else if (isOne && isTwo && isThree) {
// 1 1 1
_viewOneWidth.constant = 0;
_viewTwoWidth.constant = 0;
_viewThreeWidth.constant = 0;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Hoffnung Also diese Logik wird jemandem helfen.
In meinem Fall setze ich die Konstante der height constraint auf 0.0f
und auch die hidden
-Eigenschaft auf YES
.
Um die Ansicht (mit den Subviews) wieder anzuzeigen, habe ich das Gegenteil getan: Ich habe die Höhenkonstante auf einen Wert ungleich Null gesetzt und die hidden
-Eigenschaft auf NO
gesetzt.
Dies ist eine andere Lösung mit Prioritätsbeschränkung. Die Idee ist die Breite auf 0 gesetzt.
erstellen Sie eine Inhaltsansicht (rot) und setzen Sie den Nachlauf 10pt auf Superview (orange). Beachten Sie nachfolgende Leerzeichen-Einschränkungen. Es gibt zwei nachfolgende Einschränkungen mit unterschiedlicher Priorität. Low (= 10) und High (<= 10). Dies ist wichtig, um Mehrdeutigkeiten zu vermeiden .
Setzen Sie die Breite der orangefarbenen Ansicht auf 0, um die Ansicht auszublenden .
Wie in no_scene vorgeschlagen, können Sie dies definitiv tun, indem Sie die Priorität der Einschränkung zur Laufzeit ändern. Dies war für mich viel einfacher, da ich mehr als eine blockierende Sicht hatte, die entfernt werden müsste.
Hier ist ein Ausschnitt aus ReactiveCocoa:
RACSignal* isViewOneHiddenSignal = RACObserve(self.viewModel, isViewOneHidden);
RACSignal* isViewTwoHiddenSignal = RACObserve(self.viewModel, isViewTwoHidden);
RACSignal* isViewThreeHiddenSignal = RACObserve(self.viewModel, isViewThreeHidden);
RAC(self.viewOne, hidden) = isViewOneHiddenSignal;
RAC(self.viewTwo, hidden) = isViewTwoHiddenSignal;
RAC(self.viewThree, hidden) = isViewThreeHiddenSignal;
RAC(self.viewFourBottomConstraint, priority) = [[[[RACSignal
combineLatest:@[isViewOneHiddenSignal,
isViewTwoHiddenSignal,
isViewThreeHiddenSignal]]
and]
distinctUntilChanged]
map:^id(NSNumber* allAreHidden) {
return [allAreHidden boolValue] ? @(780) : @(UILayoutPriorityDefaultHigh);
}];
RACSignal* updateFramesSignal = [RACObserve(self.viewFourBottomConstraint, priority) distinctUntilChanged];
[updateFramesSignal
subscribeNext:^(id x) {
@strongify(self);
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3 animations:^{
[self.view layoutIfNeeded];
}];
}];
Ich denke, das ist die einfachste Antwort. Bitte überprüfen Sie, ob sie gut funktioniert
StackFullView.layer.isHidden = true
Task_TopSpaceSections.constant = 0. //your constrain of top view
überprüfen Sie hier https://www.youtube.com/watch?v=EBulMWMoFuw
So würde ich meine Ansichten neu ausrichten, um Ihre Lösung zu erhalten:
Ich habe eine eigene Daumenregel erstellt. Wenn Sie eine Uiview, deren Einschränkungen möglicherweise betroffen sind, ein-/ausblenden möchten, fügen Sie alle betroffenen/abhängigen Unteransichten in einer Uiview hinzu und aktualisieren die Konstante für die führende/nachlaufende/obere/untere Bedingung programmgesteuert.
Falls dies jemandem hilft, habe ich eine Hilfsklasse für die Verwendung von visuellem Format Einschränkungen erstellt. Ich verwende es in meiner aktuellen App.
Es könnte ein wenig auf meine Bedürfnisse zugeschnitten sein, aber Sie finden es vielleicht nützlich oder möchten es modifizieren und einen eigenen Helfer erstellen.
Ich danke Tim für seine Antwort oben , diese Antwort zu UIScrollView und auch diese Anleitung .
der beste Weg, dies zu tun, ist das Deaktivieren von Einschränkungen mit isActive = false. Beachten Sie jedoch, dass das Deaktivieren einer Einschränkung sie entfernt und freigibt, sodass Sie über starke Auslässe verfügen müssen.
Dies ist eine alte Frage, aber ich hoffe trotzdem, dass es hilft. Von Android aus haben Sie auf dieser Plattform eine praktische Methode, isVisible
, um sie aus der Ansicht auszublenden, aber nicht den Rahmen berücksichtigen, wenn das automatische Layout die Ansicht zeichnet.
mit extension und "extend" uiview könnten Sie eine ähnliche Funktion in ios ausführen (nicht sicher, warum es nicht bereits in UIKit ist) Hier eine Implementierung in Swift 3:
func isVisible(_ isVisible: Bool) {
self.isHidden = !isVisible
self.translatesAutoresizingMaskIntoConstraints = isVisible
if isVisible { //if visible we remove the hight constraint
if let constraint = (self.constraints.filter{$0.firstAttribute == .height}.first){
self.removeConstraint(constraint)
}
} else { //if not visible we add a constraint to force the view to have a hight set to 0
let height = NSLayoutConstraint(item: self, attribute: .height, relatedBy: .equal , toItem: nil, attribute: .notAnAttribute, multiplier: 0, constant: 0)
self.addConstraint(height)
}
self.layoutIfNeeded()
}
Ich werde die horizontale Stapelansicht verwenden. Es kann den Rahmen entfernen, wenn die Unteransicht ausgeblendet ist.
In der Abbildung unten ist die rote Ansicht der eigentliche Container für Ihren Inhalt und enthält 10pt Leerzeichen bis zum orangefarbenen Superview (ShowHideView). Verbinden Sie dann ShowHideView einfach mit IBOutlet und zeigen Sie es programmatisch an.