Attualmente sto avendo difficoltà a capire perché il seguente test dell'unità non funziona su un iPad 2. Il layout automatico sembra leggermente 0,5 punti) mis-position view
all'interno di superview
relativo al centraggio esatto richiesto da due vincoli di layout. Ciò che sembra particolarmente strano è che il test cruciale (ma ultima asserzione) passa su un iPhone 5, quindi l'errore di arrotondamento apparente interessa solo una piattaforma (iOS 6). Cosa sta succedendo qui?Perché il layout automatico di iOS causa errori di arrotondamento apparenti sui display pre-Retina (test unitario incluso)
UPDATE 1 ho cambiato il codice per garantire che entrambi i fotogrammi che siano sufficientemente limitate in termini di larghezze e altezze anche se translatesAutoresizingMaskIntoConstraints
è NO
, come suggerito come rimedio eventualmente correlato here. Tuttavia, questo a quanto pare non cambia la situazione.
#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 ho isolato un altro esempio di (apparentemente) lo stesso problema in un secondo test di unità. Questa volta comporta un vincolo in alto (non al centro), e questa volta una coordinata punto frazionaria sembra essere l'innesco. (Il test ha esito positivo anche su dispositivi pre-Retina, ad esempio con y = 951
, ovvero una coordinata di punti dispari.) Ho verificato in varie configurazioni del simulatore (accanto al mio iPad 2 fisico e iPhone 5) la comparsa sembra legata all'assenza di una Ratina display. (Di nuovo, grazie a @ArkadiuszHolko per il lead.)
Il mio senso corrente di questi test è che bisogna evitare altezze dispari e coordinate y frazionali se è necessario disporre di layout auto point-esatto su display pre-retina. Ma perché?
- (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?
}
accade solo su iPad 2 su iOS 6? –
@ArkadiuszHolko Il problema si presenta su iPad 2 con iOS 6.1.3. Non viene visualizzato su iPhone 5 con iOS 6.1.4. Queste sono le ultime versioni di iOS 6. Al momento non ho i mezzi per testare su iOS 7. Cos'altro potrei provare? – Drux
Riesci a vedere cosa succede quando cambi l'altezza della 'vista' da 21 a 22? I risultati ora sono coerenti tra iPhone e iPad? iPad non ha il display retina, che potrebbe aver causato la differenza. –