chr*_*838 330 xcode objective-c ios autolayout
我想使用AutoLayout以一种让人联想到UIImageView的宽高比内容模式的方式来调整和布局视图.
我在Interface Builder的容器视图中有一个子视图.子视图具有一些我希望尊重的固有宽高比.容器视图的大小在运行时之前是未知的.
如果容器视图的宽高比比子视图宽,那么我希望子视图的高度等于父视图的高度.
如果容器视图的宽高比高于子视图,那么我希望子视图的宽度等于父视图的宽度.
在任何一种情况下,我都希望子视图在容器视图中水平和垂直居中.
有没有办法在Xcode 6或以前的版本中使用AutoLayout约束来实现这一点?理想情况下使用Interface Builder,但如果没有,也许可以通过编程方式定义这些约束.
rob*_*off 1040
你没有描述适合的尺度; 你正在描述方面适合.(我已经在这方面编辑了你的问题.)子视图变得尽可能大,同时保持其纵横比并完全适合其父级.
无论如何,您可以使用自动布局执行此操作.你可以在IB Xcode 5.1中完全完成它.让我们从一些观点开始:

浅绿色视图的纵横比为4:1.深绿色视图的纵横比为1:4.我将设置约束,以便蓝色视图填充屏幕的上半部分,粉红色视图填充屏幕的下半部分,每个绿色视图尽可能地扩展,同时保持其纵横比并适合其容器.
首先,我将在蓝色视图的所有四个边上创建约束.我会将它固定到每条边上最近的邻居,距离为0.我确保关闭边距:

请注意,我还没有更新框架.我发现在设置约束时在视图之间留出空间更容易,只需手动将常量设置为0(或其他).
接下来,我将粉红色视图的左,下,右边缘固定到最近的邻居.我不需要设置上边缘约束,因为它的上边缘已经被约束到蓝色视图的下边缘.

我还需要粉红色和蓝色视图之间的等高限制.这将使他们每个填充屏幕的一半:

如果我告诉Xcode现在更新所有帧,我得到这个:

所以我到目前为止设置的约束是正确的.我将其撤消并开始处理浅绿色视图.
方面拟合浅绿色视图需要五个约束:
让我们考虑两个宽度约束.小于或等于约束本身不足以确定浅绿色视图的宽度; 许多宽度将适合约束.由于存在歧义,autolayout将尝试选择最小化另一个(高优先级但不是必需的)约束中的错误的解决方案.最小化错误意味着使宽度尽可能接近容器的宽度,同时不违反所需的小于或等于约束.
高度约束也会发生同样的事情.并且由于还需要宽高比约束,它只能沿一个轴最大化子视图的大小(除非容器恰好具有与子视图相同的宽高比).
首先我创建宽高比约束:

然后我用容器创建相等的宽度和高度约束:

我需要将这些约束编辑为小于或等于约束:

接下来,我需要使用容器创建另一组相等的宽度和高度约束:

我需要使这些新约束低于所需的优先级:

最后,您要求子视图在其容器中居中,因此我将设置这些约束:

现在,为了测试,我将选择视图控制器并让Xcode更新所有帧.这就是我得到的:

哎呀!子视图已扩展为完全填充其容器.如果我选择它,我可以看到它实际上保持了它的宽高比,但它正在进行方面填充而不是方面适合.
问题在于,在约束小于或等于的情况下,哪个视图位于约束的每一端都很重要,并且Xcode设置了与我的期望相反的约束.我可以选择两个约束中的每一个并反转它的第一个和第二个项目.相反,我只需选择子视图并将约束更改为大于或等于:

Xcode更新布局:

现在我对底部的深绿色视图做了所有相同的事情.我需要确保它的宽高比为1:4(Xcode以奇怪的方式调整大小,因为它没有约束).我不会再显示步骤,因为它们是相同的.这是结果:

现在我可以在iPhone 4S模拟器中运行它,它的屏幕尺寸与IB使用的不同,并且测试旋转:

我可以在iPhone 6模拟器中测试:

为方便起见,我已将最后的故事板上传到此要点.
Joh*_*rug 24
罗布,你的答案太棒了!我也知道这个问题具体是通过使用自动布局来实现这一点.但是,作为参考,我想展示如何在代码中完成此操作.您可以设置顶部和底部视图(蓝色和粉红色),就像Rob所示.然后你创建一个自定义AspectFitView:
AspectFitView.h:
#import <UIKit/UIKit.h>
@interface AspectFitView : UIView
@property (nonatomic, strong) UIView *childView;
@end
AspectFitView.m:
#import "AspectFitView.h"
@implementation AspectFitView
- (void)setChildView:(UIView *)childView
{
    if (_childView) {
        [_childView removeFromSuperview];
    }
    _childView = childView;
    [self addSubview:childView];
    [self setNeedsLayout];
}
- (void)layoutSubviews
{
    [super layoutSubviews];
    if (_childView) {
        CGSize childSize = _childView.frame.size;
        CGSize parentSize = self.frame.size;
        CGFloat aspectRatioForHeight = childSize.width / childSize.height;
        CGFloat aspectRatioForWidth = childSize.height / childSize.width;
        if ((parentSize.height * aspectRatioForHeight) > parentSize.height) {
            // whole height, adjust width
            CGFloat width = parentSize.width * aspectRatioForWidth;
            _childView.frame = CGRectMake((parentSize.width - width) / 2.0, 0, width, parentSize.height);
        } else {
            // whole width, adjust height
            CGFloat height = parentSize.height * aspectRatioForHeight;
            _childView.frame = CGRectMake(0, (parentSize.height - height) / 2.0, parentSize.width, height);
        }
    }
}
@end
接下来,您将故事板中的蓝色和粉红色视图的类更改为AspectFitViews.最后,你设置两个出口到您的视图-控制topAspectFitView和bottomAspectFitView并设置其childView为s viewDidLoad:
- (void)viewDidLoad {
    [super viewDidLoad];
    UIView *top = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 100)];
    top.backgroundColor = [UIColor lightGrayColor];
    UIView *bottom = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 500)];
    bottom.backgroundColor = [UIColor greenColor];
    _topAspectFitView.childView = top;
    _bottomAspectFitView.childView = bottom;
}
因此,在代码中执行此操作并不难,它仍然具有很强的适应性,可以使用不同大小的视图和不同的宽高比.
2015年7月更新:在此处查找演示应用程序:https://github.com/jfahrenkrug/SPWKAspectFitView
bri*_*ple 11
这适用于 macOS。
我在使用 Rob 的方式在 OS X 应用程序上实现方面拟合时遇到问题。但我用另一种方式制作它——我没有使用宽度和高度,而是使用前导、尾随、顶部和底部空间。
基本上,添加两个前导空格,其中一个是 >= 0 @1000 所需优先级,另一个是 = 0 @250 低优先级。对尾随、顶部和底部空间进行相同的设置。
当然,您需要设置纵横比和中心 X 和中心 Y。
然后工作就完成了!
我需要一个接受答案的解决方案,但是从代码中执行.我发现最优雅的方法是使用Masonry框架.
#import "Masonry.h"
...
[view mas_makeConstraints:^(MASConstraintMaker *make) {
    make.width.equalTo(view.mas_height).multipliedBy(aspectRatio);
    make.size.lessThanOrEqualTo(superview);
    make.size.equalTo(superview).with.priorityHigh();
    make.center.equalTo(superview);
}];
我发现自己想要纵横填充行为,以便 UIImageView 保持自己的纵横比并完全填充容器视图。令人困惑的是,我的 UIImageView 打破了高优先级等宽和等高约束(在 Rob 的回答中描述)并以全分辨率渲染。
解决方法很简单,就是将 UIImageView 的 Content Compression Resistance Priority 设置为低于等宽等高约束的优先级:

| 归档时间: | 
 | 
| 查看次数: | 92116 次 | 
| 最近记录: |