为什么iOS自动布局导致Pre-Retina显示屏之前出现明显的舍入误差(包括单元测试)

前端之家收集整理的这篇文章主要介绍了为什么iOS自动布局导致Pre-Retina显示屏之前出现明显的舍入误差(包括单元测试)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我目前很难理解为什么以下单元测试在iPad 2上失败.自动布局似乎略微(0.5分)在超视图内部的错位置视图相对于两个布局约束所要求的精确对中.似乎特别奇怪的是,关键的测试(但最后的断言)通过iPhone 5,所以明显的舍入误差仅影响一个(iOS 6)平台.这里发生了什么?

更新1我已经改变了代码,以确保两个框架在宽度和高度方面都受到足够的约束,即使转换为AutotoresizingMaskIntoConstraints为NO,建议作为可能的相关补救措施here.但是,这显然不会改变这种情况.

  1. #import "BugTests.h"
  2.  
  3. @implementation BugTests
  4.  
  5. - (void)testCenteredLayout {
  6. UIView *superview = [[UIView alloc] initWithFrame:CGRectMake(0,768,88)];
  7. superview.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
  8. superview.translatesAutoresizingMaskIntoConstraints = YES;
  9.  
  10. UILabel *view = [[UILabel alloc] initWithFrame:CGRectMake(0,0)];
  11. view.text = @"Single Round against iPad.";
  12. view.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
  13. view.translatesAutoresizingMaskIntoConstraints = NO;
  14. [view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:206.0]];
  15. [view addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant: 21.0]];
  16.  
  17. [superview addSubview:view];
  18.  
  19. [superview addConstraint:[NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]];
  20. [superview addConstraint:[NSLayoutConstraint constraintWithItem:superview attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]];
  21.  
  22. STAssertEquals(superview.center,CGPointMake(384,44),nil); // succeeds
  23. STAssertEquals(view.center,CGPointMake( 0,0),nil); // succeeds
  24.  
  25. [superview setNeedsLayout];
  26. [superview layoutIfNeeded];
  27.  
  28. STAssertTrue(!superview.hasAmbiguousLayout,nil);
  29.  
  30. STAssertEquals(superview.frame.size,CGSizeMake(768,88),nil); // succeeds
  31. STAssertEquals(view.frame.size,CGSizeMake(206,21),nil); // succeeds
  32.  
  33. STAssertEquals(superview.center,view.center,nil); // fails: why?
  34. STAssertEquals(view.center,44.5),nil); // succeeds: why?
  35. }
  36.  
  37. @end

更新2我在另一个单元测试中孤立了另一个(显然)同一个问题的实例.这一次它涉及顶部(而不是中心)的约束,而这次分数点坐标似乎是触发器. (测试也可以在Retina设备上成功,例如y = 951,即一个奇点坐标).我已经检查了各种模拟器配置(我的物理iPad 2和iPhone 5旁边)的确发生似乎与没有一个Ratina显示. (再次感谢@ArkadiuszHolko领先.)

我目前从这些测试的感觉是,如果需要在Retina显示器上进行点精确自动布局,则必须避免奇异的高度和小数y坐标.但为什么?

  1. - (void)testNonRetinaAutoLayoutProblem2 {
  2. UIView *superview = [[UIView alloc] initWithFrame:CGRectMake(0,1004)];
  3. superview.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
  4. superview.translatesAutoresizingMaskIntoConstraints = YES;
  5.  
  6. CGFloat y = 950.5; // see e.g. pageControlTopConstraint
  7.  
  8. UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0,0)];
  9. view.translatesAutoresizingMaskIntoConstraints = NO;
  10. [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0.0]];
  11. [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0.0]];
  12. [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:y]];
  13. [superview addConstraint:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:8]];
  14.  
  15. [superview addSubview:view];
  16.  
  17. [superview setNeedsLayout];
  18. [superview layoutIfNeeded];
  19.  
  20. STAssertTrue(!superview.hasAmbiguousLayout,nil);
  21. STAssertTrue(!view.hasAmbiguousLayout,nil);
  22.  
  23. STAssertEquals(superview.frame,CGRectMake(0,1004),nil); // succeeds
  24. STAssertEquals(view.frame,y,8),nil); // fails: why?
  25. STAssertEquals(view.frame,y + 0.5,nil); // succeeds: why?
  26. }

解决方法

你所看到的是,自动布局憎恶不一致的观点.在非视网膜设备上,最接近的像素是最接近的点,因此它会舍入到整数.在视网膜屏幕上,最接近的像素是最接近的半点,所以它最接近最接近的0.5.您可以通过将第二个测试中的y更改为950.25,并注意到view.frame保留{{0,95.5},{768,8}}(而不是更改为{{0,95.25}} {768,8}} }).

(只是为了证明它是四舍五入而不是天花板,如果你将y更改为950.2 view.frame成为{{0,950} {{{8},8}}}.

猜你在找的iOS相关文章