我想使用AutoLayout以一种让人联想到UIImageView的方面适合内容模式的方式来大小和布局视图。
我在接口生成器的容器视图中有一个子视图。子视图有一些固有的纵横比,我希望尊重它。容器视图的大小在运行时之前是未知的。
如果容器视图的纵横比比子视图宽,那么我希望子视图的高度等于父视图的高度。
如果容器视图的纵横比大于子视图,那么我希望子视图的宽度等于父视图的宽度。
在这两种情况下,我希望子视图在容器视图中水平和垂直居中。
在Xcode 6或之前的版本中,是否有一种方法可以使用AutoLayout约束来实现这一点?理想情况下使用Interface Builder,但如果不是,也许可以通过编程方式定义这样的约束。
罗伯,你的答案太棒了!
我也知道这个问题是专门关于实现这一点使用自动布局。但是,作为参考,我想展示如何在代码中实现这一点。像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,并在viewDidLoad中设置它们的childViews:
- (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
我找不到任何现成的完全程序化的解决方案,所以这里是我在swift 5中对方面填充扩展到视图的看法:
extension UIView {
public enum FillingMode {
case full(padding:Int = 0)
case aspectFit(ratio:CGFloat)
// case aspectFill ...
}
public func addSubview(_ newView:UIView, withFillingMode fillingMode:FillingMode) {
newView.translatesAutoresizingMaskIntoConstraints = false
addSubview(newView)
switch fillingMode {
case let .full(padding):
let cgPadding = CGFloat(padding)
NSLayoutConstraint.activate([
newView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: cgPadding),
newView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -cgPadding),
newView.topAnchor.constraint(equalTo: topAnchor, constant: cgPadding),
newView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -cgPadding)
])
case let .aspectFit(ratio):
guard ratio != 0 else { return }
NSLayoutConstraint.activate([
newView.centerXAnchor.constraint(equalTo: centerXAnchor),
newView.centerYAnchor.constraint(equalTo: centerYAnchor),
newView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor),
newView.leadingAnchor.constraint(equalTo: leadingAnchor).usingPriority(900),
newView.trailingAnchor.constraint(lessThanOrEqualTo: trailingAnchor),
newView.trailingAnchor.constraint(equalTo: trailingAnchor).usingPriority(900),
newView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor),
newView.topAnchor.constraint(equalTo: topAnchor).usingPriority(900),
newView.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor),
newView.bottomAnchor.constraint(equalTo: bottomAnchor).usingPriority(900),
newView.heightAnchor.constraint(equalTo: newView.widthAnchor, multiplier: CGFloat(ratio)),
])
}
}
}
这里是优先级扩展(来自另一个线程,但我“保护它”与1…1000之间的一些模式匹配:
extension NSLayoutConstraint {
/// Returns the constraint sender with the passed priority.
///
/// - Parameter priority: The priority to be set.
/// - Returns: The sended constraint adjusted with the new priority.
func usingPriority(_ priority: Int) -> NSLayoutConstraint {
self.priority = UILayoutPriority( (1...1000 ~= priority) ? Float(priority) : 1000 )
return self
}
}
希望能有所帮助~