Ich habe derzeit Schwierigkeiten zu verstehen, warum der folgende Komponententest auf einem iPad 2 fehlschlägt. Auto-Layout scheint leicht (durch 0,5 Punkte) falsche Position view
innerhalb superview
relativ zu der genauen Zentrierung, die von zwei Layout-Einschränkungen erforderlich ist. Besonders merkwürdig erscheint, dass der entscheidende Test (aber letzte Behauptung) auf einem iPhone 5 läuft, so dass der scheinbare Rundungsfehler nur eine (iOS 6) Plattform betrifft. Was ist denn hier los?Warum führt das iOS-Auto-Layout zu scheinbaren Rundungsfehlern auf Pre-Retina-Displays (Unit-Test enthalten)
UPDATE 1 Ich habe den Code, um sicherzustellen, dass geändert, dass beide Rahmen ausreichend in Bezug auf die Breiten und Höhen beschränkt sind, auch wenn translatesAutoresizingMaskIntoConstraints
ist NO
, wie als möglicherweise im Zusammenhang Abhilfe here vorgeschlagen. Dies ändert jedoch offensichtlich nichts an der Situation.
#import "BugTests.h"
@implementation BugTests
- (void)testCenteredLayout {
UIView *superview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 768, 88)];
superview.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
superview.translatesAutoresizingMaskIntoConstraints = YES;
UILabel *view = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
view.text = @"Single Round against iPad.";
view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
view.translatesAutoresizingMaskIntoConstraints = NO;
[view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:206.0]];
[view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant: 21.0]];
[superview addSubview:view];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
STAssertEquals(superview.center, CGPointMake(384, 44), nil); // succeeds
STAssertEquals(view.center, CGPointMake( 0, 0), nil); // succeeds
[superview setNeedsLayout];
[superview layoutIfNeeded];
STAssertTrue(!superview.hasAmbiguousLayout, nil);
STAssertEquals(superview.frame.size, CGSizeMake(768, 88), nil); // succeeds
STAssertEquals(view.frame.size, CGSizeMake(206, 21), nil); // succeeds
STAssertEquals(superview.center, CGPointMake(384, 44), nil); // succeeds
STAssertEquals(superview.center, view.center, nil); // fails: why?
STAssertEquals(view.center, CGPointMake(384, 44.5), nil); // succeeds: why?
}
@end
UPDATE 2 Ich habe eine andere Instanz (scheinbar) das gleiche Problem in einer zweiten Einheit Test isoliert. Diesmal handelt es sich um eine obere (nicht zentrale) Abhängigkeit, und diesmal scheint eine gebrochene Punktkoordinate der Auslöser zu sein. (Der Test ist auch auf Pre-Retina-Geräten erfolgreich, zB mit y = 951
, also einer ungeraden Punktkoordinate.) Ich habe verschiedene Simulatorkonfigurationen eingecheckt (neben meinem physischen iPad 2 und iPhone 5), scheint in der Tat an das Fehlen eines Ratina gebunden zu sein Anzeige. (Nochmals, dank @ ArkadiuszHolko für die Führung.)
Mein aktueller Sinn dieser Tests ist, dass man ungerade Höhen und gebrochene y-Koordinaten vermeiden muss, wenn punktgenaues automatisches Layout auf Pre-Retina-Displays erforderlich ist. Aber warum?
- (void)testNonRetinaAutoLayoutProblem2 {
UIView *superview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 768, 1004)];
superview.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
superview.translatesAutoresizingMaskIntoConstraints = YES;
CGFloat y = 950.5; // see e.g. pageControlTopConstraint
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
view.translatesAutoresizingMaskIntoConstraints = NO;
[superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:y]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:8]];
[superview addSubview:view];
[superview setNeedsLayout];
[superview layoutIfNeeded];
STAssertTrue(!superview.hasAmbiguousLayout, nil);
STAssertTrue(!view.hasAmbiguousLayout, nil);
STAssertEquals(superview.frame, CGRectMake(0, 0, 768, 1004), nil); // succeeds
STAssertEquals(view.frame, CGRectMake(0, y, 768, 8), nil); // fails: why?
STAssertEquals(view.frame, CGRectMake(0, y + 0.5, 768, 8), nil); // succeeds: why?
}
es nur passieren Hat iPad 2 auf iOS 6? –
@ArkadiuszHolko Das Problem wird auf dem iPad 2 mit iOS 6.1.3 angezeigt. Es erscheint nicht auf dem iPhone 5 mit iOS 6.1.4. Dies sind die neuesten iOS 6-Versionen. Ich habe derzeit nicht die Möglichkeit, auf iOS 7 zu testen. Was könnte ich noch ausprobieren? – Drux
Können Sie sehen, was passiert, wenn Sie die Höhe der "Ansicht" von 21 auf 22 ändern? Sind die Ergebnisse zwischen iPhone und iPad nun konsistent? Das iPad hat nicht das Retina-Display, das den Unterschied verursacht haben könnte. –