iOS 8自动布局问题

时间:2014-10-09 21:08:23

标签: ios objective-c ios7 ios8 autolayout

iOS 8中出现了自动布局的烦人问题,而​​iOS 7中的设置相同。

我已经简化并隔离了有问题的情况,以及它 的工作方式 - 以及 在iOS 7中的工作原理

Constraints working in iOS 7

该功能包含一个容器视图(蓝色)和三个子视图:

  • 标签
  • 图像视图(带有切片的缩放图像)
  • 按钮

我添加了一个滑块,通过修改容器的宽度约束来控制容器视图的宽度。

自动布局约束将标签固定在左侧,按钮固定在右侧,图像视图固定在两侧,没有宽度约束。

在iOS 8中,完全相同的设置如下所示:

Constraints broken in iOS 8

注意图像视图(黑色线条)似乎如何锚定在容器视图右侧的偏移 之外。

我已经尝试了所有内容,但我无法弄清楚为什么在iOS 8中这种行为会有所不同。我已经删除并多次替换了所有约束,但我仍然得到相同的结果。

这些是在每个子视图上设置的约束,分别是:

Sub views constraints

这些是容器视图的约束:

Container view constraints

容器视图的宽度约束由滑块操纵,如下所示:

Width constraint connection

- (IBAction)handleSliderChange:(id)sender
{
    self.buttonWidth.constant = self.slider.value * 1024.0;

    [self.containerView setNeedsLayout];
    [self.containerView setNeedsUpdateConstraints];
    [self.containerView layoutIfNeeded];

    [self.view setNeedsLayout];
    [self.view setNeedsUpdateConstraints];
    [self.view layoutIfNeeded];
}

其他在iOS 8中遇到自动布局问题的人似乎已经能够通过在包含视图上直接调用setNeedsLayout和/或setNeedsUpdateConstraints 来解决类似问题这就是为什么我非常明确地在包含视图和根视图上调用它。我已经尝试了上述所有组合,但似乎没有任何区别。

我开始失去寻找解决方案的希望,但也许这里的某个人已经处理过类似的情况并且能够清楚地解决这个问题吗?


编辑:我应该补充一点,我还尝试设置constraints from the image view to the label and button而不是包含视图的边缘,结果相同。


编辑2:以下是我尝试隔离问题时使用的测试项目: Download

3 个答案:

答案 0 :(得分:7)

这不是自动布局的问题,但必须是iOS 8中关于处理切片图像资源的错误。

使用您的示例项目:

    UIImage *img = [UIImage imageNamed:@"pointer-dark-left"];
    NSLog(@"alignmentRect: %@", NSStringFromUIEdgeInsets(img.alignmentRectInsets));
    NSLog(@"capInsets: %@", NSStringFromUIEdgeInsets(img.capInsets));

此代码打印

// iOS 7
alignmentRect: {0, 0, 0, 0}
capInsets: {0, 5.5, 0, 134}

// iOS 8
alignmentRect: {0, 0, 0, 65.5}
capInsets: {0, 5.5, 0, 134}

alignmentRectInsets.right65.5

作为documented,Autolayout适用于对齐矩形,UIImageView使用其图像alignmentRectInsets。因此,self.line65.5 pt额外的正确宽度。

当然,您没有在xcassets编辑器中设置对齐插件,我相信这是错误

screenshot

这是一个丑陋但有效的解决方法:(

- (void)viewDidLoad {
    [super viewDidLoad];
    self.line.image = [self.line.image imageWithAlignmentRectInsets:UIEdgeInsetsZero];
}

答案 1 :(得分:1)

我认为你把你的约束错误连接了。

我构建了一个具有相同组件的应用程序,它运行良好。也许您可以清除所有约束并重新设置。

我添加代码以编程方式执行。

#import "ViewController.h"

@interface ViewController () {    
    NSLayoutConstraint* csViewWidth;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    NSDictionary *views = @{
                        @"label": self.uiLabel,
                        @"image": self.uiImage,
                        @"button": self.uiButton
                        };

    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[label]-[image]-[button]-|"
                                                                options:0
                                                                metrics:nil
                                                                  views:views];
    [self.view addConstraints:constraints];

    NSArray *panelConstraint = [NSLayoutConstraint constraintsWithVisualFormat:@"H:[panel(320)]" options:0 metrics:nil views:@{ @"panel": self.uiPanel }];
    csViewWidth = [panelConstraint firstObject];
    [self.view addConstraints:@[csViewWidth]];
}

- (IBAction)onSliderChanged:(UISlider*)sender {
    float containerWidth = self.view.frame.size.width;
    csViewWidth.constant = sender.value * containerWidth;
}

@end

此解决方案经过测试且运行正常。 无需调用setNeedsLayout和layoutIfNeeded。

答案 2 :(得分:0)

这不是因为iOS错误

图像被错误切割

我测试了您的项目,现在按预期工作。

  

切片必须如下所示:

     

0 | - | ----------- |

     
      
  • 第一:圈子后面
  •   
  • 第二个:第一个单位
  • 之后   
  • 第三名:在最后
  •   

通过你的切片,你告诉ios采取长尾巴,这会破坏你的布局。