2013-10-13 7 views
12

Şu anda aşağıdaki birim test bir iPad 2. Otomatik düzeni başarısız neden zor anlar anlama yaşıyorum biraz görünüyor iOS otomatik düzen kurşun yapar Iki düzen kısıtlaması tarafından gereken tam merkezleme göre superview içinde view yanlış konum 0,5 puan). Özellikle garip görünen şey, çok önemli bir testin (ama son onaylama) bir iPhone 5'e geçmesidir, dolayısıyla görünen yuvarlama hatası sadece bir (iOS 6) platformu etkiler. Burada neler oluyor? Bir olasılıkla ilgili ilaç here olarak önerildiği gibiNeden tarafından (önceden Retina ekranlarda görünen yuvarlama hataları (birim testi dahil)

GÜNCELLEME 1 Ben, her iki çerçeve yeterince, genişliği ve yüksekliği bakımından sıkıntılar olduğunu bile translatesAutoresizingMaskIntoConstraintsNO olmasını sağlamak için kod değiştirdik. Ancak, görünüşe göre bu durum durumu değiştirmez.

#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 

GÜNCELLEME 2 bir ikinci birim test (görünüşte) aynı problem başka bir örneğini izole ettik. Bu sefer bir üst (ortada değil) kısıtlaması içerir ve bu sefer bir fraksiyonel nokta koordinatı tetikleyici gibi görünür. (Test aynı zamanda Retina öncesi cihazlarda da başarılı olur, örneğin y = 951, yani bir tek nokta koordinatı.) Çeşitli simülatör konfigürasyonlarında (fiziksel iPad 2 ve iPhone 5'in yanında) kontrol ettim aslında bir Ratina'nın yokluğuna bağlı görünüyor. Görüntüle. (Önceden @ArkadiuszHolko'ya teşekkür ederiz.)

Bu testlerden elde ettiğim şu anki anlam, Retina öncesi görüntüler üzerinde nokta-kesin otomatik yerleşimin gerekli olması halinde tek bir yükseklik ve kesirli y-koordinatlarından kaçınması gerektiğidir. Ama neden?

- (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? 
} 
+0

sadece üzerinde olur mu iOS 6'daki iPad 2? –

+0

@ArkadiuszHolko Sorun, iOS 6.1.3'te çalışan iPad 2'de gösteriliyor. IOS 6.1.4 çalıştıran iPhone 5'te görünmüyor. Bunlar en son iOS 6 sürümleridir. Şu anda iOS 7'de test etme imkanım yok. Başka neler deneyebilirim? – Drux

+1

Görünümün yüksekliğini 21'den 22'ye değiştirdiğinizde ne olduğunu görebiliyor musunuz? Sonuçlar artık iPhone ve iPad arasında tutarlı mı? iPad'in retina ekranı yok, bu da farklılığa neden olmuş olabilir. –

cevap

11

Gösterdiğiniz şey, otomatik oynatmanın yanlış hizalanmış görünümlerden kaçınmasıdır. Retina olmayan cihazlarda en yakın piksel en yakın nokta, bu nedenle tam sayılara yuvarlar. Retina ekranlarında en yakın piksel en yakın yarım noktasıdır, bu yüzden en yakın olana yuvarlar .5. Bunu ikinci testinizdeki y'yi 950.25 olarak değiştirerek ve view.frame'in {{0, 950.5}, {768, 8}} kaldığını belirterek ({{0, 950.25}, {768, 8} şeklinde değiştirmek yerine bunu gösterebilirsiniz. }).

(Sadece 950,2 view.frame olur Sizin y değiştirirseniz o {{0, 950} {768, 8}}, yuvarlama ve ceil ing olduğunu kanıtlamak için.)

+0

Bu nedenle, görüntülemelerin tam piksel koordinatlarıyla tam olarak hizalanması gereken zımni bir kısıtlama, tüm açık kısıtlamalardan daha yüksek önceliğe sahiptir, sanırım ... – Drux