iOS 8中出现了自动布局的烦人问题,而iOS 7中的设置相同。
我已经简化并隔离了有问题的情况,以及它 的工作方式 - 以及 在iOS 7中的工作原理
该功能包含一个容器视图(蓝色)和三个子视图:
我添加了一个滑块,通过修改容器的宽度约束来控制容器视图的宽度。
自动布局约束将标签固定在左侧,按钮固定在右侧,图像视图固定在两侧,没有宽度约束。
在iOS 8中,完全相同的设置如下所示:
注意图像视图(黑色线条)似乎如何锚定在容器视图右侧的偏移 之外。
我已经尝试了所有内容,但我无法弄清楚为什么在iOS 8中这种行为会有所不同。我已经删除并多次替换了所有约束,但我仍然得到相同的结果。
这些是在每个子视图上设置的约束,分别是:
这些是容器视图的约束:
容器视图的宽度约束由滑块操纵,如下所示:
- (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
答案 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.right
是65.5
!
作为documented,Autolayout适用于对齐矩形,UIImageView
使用其图像alignmentRectInsets
。因此,self.line
有65.5
pt额外的正确宽度。
当然,您没有在xcassets
编辑器中设置对齐插件,我相信这是错误。
这是一个丑陋但有效的解决方法:(
- (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)
我测试了您的项目,现在按预期工作。
切片必须如下所示:
0 | - | ----------- |
- 第一:圈子后面
- 第二个:第一个单位
之后- 第三名:在最后
通过你的切片,你告诉ios采取长尾巴,这会破坏你的布局。