14

現在、次の単体テストが iPad 2 で失敗する理由を理解するのに苦労しています。自動レイアウトは、2 つのレイアウト制約で必要とされる正確なセンタリングに対して、view内部でわずかに (0.5 ポイント) ずれているようです。superview特に奇妙に思われるのは、重要なテスト (最後のアサーション) が iPhone 5 で合格するため、明らかな丸め誤差が 1 つの (iOS 6) プラットフォームのみに影響することです。何が起きてる?

更新 1コードを変更して、両方のフレームが幅と高さに関して十分に制限されていることを確認translatesAutoresizingMaskIntoConstraintsNOまし。しかし、これは明らかに状況を変えません。

#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

更新 2 2回目の単体テストで (明らかに) 同じ問題の別のインスタンスを分離しました。今回は上(中央ではない)の拘束が含まれており、今回は分数点座標がトリガーのようです。(このテストは、Retina 以前のデバイスでも成功します。たとえばy = 951、奇数点座標を使用します。) さまざまなシミュレーター構成 (物理的な iPad 2 および iPhone 5 の隣) をチェックしましたが、発生は実際に Ratina ディスプレイがないことに関連しているようです。 . (繰り返しになりますが、リードしてくれた@ArkadiuszHolkoに感謝します。)

これらのテストからの私の現在の感覚は、Retina 以前のディスプレイで正確な自動レイアウトが必要な場合、奇数の高さと分数の y 座標を避ける必要があるということです。しかし、なぜ?

- (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?
}
4

1 に答える 1

15

あなたが示したのは、自動レイアウトが位置合わせされていないビューを嫌うということです。Retina 以外のデバイスでは、最も近いピクセルが最も近いポイントであるため、整数に丸められます。Retina スクリーンでは、最も近いピクセルが最も近い2 分の 1 ポイントであるため、最も近い .5 に丸められます。これは、2 番目のテストで y を 950.25 に変更することで実証できます。 })。

ceil( y を 950.2 に変更すると、丸めであって ing ではないことを証明するために、 view.frame は {{0, 950}, {768, 8}} になります。)

于 2013-10-16T04:56:46.760 に答える