Dou*_*ith 50 objective-c uiimageview ios autolayout nslayoutconstraint
我希望我UIImageView
的增长或缩小取决于它显示的实际图像的大小.但我希望它保持垂直居中,距离超视距的前沿10分钟.
但是,如果我设置这两个约束,它会抱怨我没有设置足够的约束来满足自动布局.对我来说,它似乎完美地描述了我想要的东西.我错过了什么?
小智 68
图像视图的内在大小已经取决于图像的大小.你的假设(和约束是正确的).
但是,如果您在界面构建器中设置了图像视图并且没有为其提供图像,则布局系统(界面构建器)将不知道图像视图在编译时应该有多大.您的布局不明确,因为您的图片视图可能有多种尺寸.这就是抛出错误的原因.
设置图像视图的图像属性后,图像视图的内在大小由图像的大小定义.如果您在运行时设置视图,那么您可以完全按照Anna提到的内容进行操作,并在图像视图的属性检查器中为界面构建器提供"占位符"内在大小.这告诉界面构建器,"现在使用这个大小,我稍后会给你一个真实的大小".占位符约束在运行时被忽略.
您的另一个选择是直接将图像分配给界面构建器中的图像视图(但我假设您的图像是动态的,因此这对您不起作用).
alg*_*gal 38
这是一个基本问题:UIImageView
与Auto Layout交互的唯一方法是通过其intrinsicContentSize
属性.该属性提供了图像本身的内在大小,仅此而已.这创造了三种情况,具有不同的解决方案
在第一种情况下,如果您UIImageView
在外部自动布局约束仅影响其位置的上下文中放置,则视图intrinsicContentSize
将声明它想要成为其图像的大小,并且自动布局将自动调整视图的大小以等于它的形象.这有时候正是你想要的,然后生活就好了!
在其他时候,你处于不同的情况.您确切知道图像视图的大小,但您还希望它保留显示图像的宽高比.在这种情况下,您可以使用"自动布局"约束图像的大小,同时在图像视图上将旧contentMode
属性设置为.scaleAspectFit
.该属性将导致图像视图重新缩放显示的图像,根据需要添加填充.如果这是你想要的,生活就是美好的!
但有时候,你处于棘手的第三种情况.您希望使用"自动布局"来部分确定视图的大小,同时允许图像的宽高比确定其他部分.例如,您可能希望使用"自动布局"约束来确定大小的一个维度(如宽度,在垂直时间轴滚动中),同时依靠视图告诉"自动布局"它需要高度与图像的纵横比匹配(所以可滚动的项目不会太短或太高.
您无法配置普通图像视图来执行此操作,因为图像视图仅与其通信intrinsicContentSize
.因此,如果将图像视图放在自动布局约束一个维度的上下文中(例如,将其约束为较短的宽度),则图像视图不会告诉自动布局它希望其高度重新缩放.它继续报告其内在的内容大小,图像本身的未修改高度.
为了配置图像视图以告诉自动布局它想要采用它包含的图像的纵横比,您需要为该效果添加新约束.此外,每当更新图像本身时,您都需要更新该约束.您可以构建一个UIImageView
执行此操作的子类,因此行为是自动的.这是一个例子:
public class ScaleAspectFitImageView : UIImageView {
/// constraint to maintain same aspect ratio as the image
private var aspectRatioConstraint:NSLayoutConstraint? = nil
required public init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
self.setup()
}
public override init(frame:CGRect) {
super.init(frame:frame)
self.setup()
}
public override init(image: UIImage!) {
super.init(image:image)
self.setup()
}
public override init(image: UIImage!, highlightedImage: UIImage?) {
super.init(image:image,highlightedImage:highlightedImage)
self.setup()
}
override public var image: UIImage? {
didSet {
self.updateAspectRatioConstraint()
}
}
private func setup() {
self.contentMode = .scaleAspectFit
self.updateAspectRatioConstraint()
}
/// Removes any pre-existing aspect ratio constraint, and adds a new one based on the current image
private func updateAspectRatioConstraint() {
// remove any existing aspect ratio constraint
if let c = self.aspectRatioConstraint {
self.removeConstraint(c)
}
self.aspectRatioConstraint = nil
if let imageSize = image?.size, imageSize.height != 0
{
let aspectRatio = imageSize.width / imageSize.height
let c = NSLayoutConstraint(item: self, attribute: .width,
relatedBy: .equal,
toItem: self, attribute: .height,
multiplier: aspectRatio, constant: 0)
// a priority above fitting size level and below low
c.priority = (UILayoutPriorityDefaultLow + UILayoutPriorityFittingSizeLevel) / 2.0
self.addConstraint(c)
self.aspectRatioConstraint = c
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个要点可以提供更多评论
xir*_*rix 11
对于@algal案例3,我所要做的就是
class ScaledHeightImageView: UIImageView {
override var intrinsicContentSize: CGSize {
if let myImage = self.image {
let myImageWidth = myImage.size.width
let myImageHeight = myImage.size.height
let myViewWidth = self.frame.size.width
let ratio = myViewWidth/myImageWidth
let scaledHeight = myImageHeight * ratio
return CGSize(width: myViewWidth, height: scaledHeight)
}
return CGSize(width: -1.0, height: -1.0)
}
}
Run Code Online (Sandbox Code Playgroud)
这会缩放intrinsicContentSize的高度分量.没有图像时返回(-1.0,-1.0),因为这是超类中的默认行为.
此外,我不需要为UITableViewAutomaticDimension
包含图像视图的单元格设置表格,并且单元格仍然自动调整大小.图像视图的内容模式是Aspect Fit
.
这是一个AspectFit
UIImageView
派生的实现,当只有一个维度受到约束时,它可以与自动布局一起使用。另一项将自动设置。它将保持图像的长宽比,并且不会在图像周围添加任何边距。
它是@algal idea的 Objective-C 实现的调整,具有以下差异:
priority = (UILayoutPriorityDefaultLow +
UILayoutPriorityFittingSizeLevel) / 2.0
计算结果为 的表达式150
不足以超越1000
默认图像内容大小约束的优先级。1000
因此方面约束优先级也增加了。image
setter 可以被多次调用,因此最好不要在此处引起额外的布局计算。required public init?(coder
aDecoder: NSCoder)
和public override init(frame:CGRect)
,所以这两个被去掉了。它们不会被 覆盖UIImageView
,这就是为什么在设置图像之前没有添加方面约束的原因。AspectKeepUIImageView.h
:
NS_ASSUME_NONNULL_BEGIN
@interface AspectKeepUIImageView : UIImageView
- (instancetype)initWithImage:(nullable UIImage *)image;
- (instancetype)initWithImage:(nullable UIImage *)image highlightedImage:(nullable UIImage *)highlightedImage;
@end
NS_ASSUME_NONNULL_END
Run Code Online (Sandbox Code Playgroud)
AspectKeepUIImageView.m
:
#import "AspectKeepUIImageView.h"
@implementation AspectKeepUIImageView
{
NSLayoutConstraint *_aspectContraint;
}
- (instancetype)initWithImage:(nullable UIImage *)image
{
self = [super initWithImage:image];
[self initInternal];
return self;
}
- (instancetype)initWithImage:(nullable UIImage *)image highlightedImage:(nullable UIImage *)highlightedImage
{
self = [super initWithImage:image highlightedImage:highlightedImage];
[self initInternal];
return self;
}
- (void)initInternal
{
self.contentMode = UIViewContentModeScaleAspectFit;
[self updateAspectConstraint];
}
- (void)setImage:(UIImage *)image
{
[super setImage:image];
[self updateAspectConstraint];
}
- (void)updateAspectConstraint
{
CGSize imageSize = self.image.size;
CGFloat aspectRatio = imageSize.height > 0.0f
? imageSize.width / imageSize.height
: 0.0f;
if (_aspectContraint.multiplier != aspectRatio)
{
[self removeConstraint:_aspectContraint];
_aspectContraint =
[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeHeight
multiplier:aspectRatio
constant:0.f];
_aspectContraint.priority = UILayoutPriorityRequired;
[self addConstraint:_aspectContraint];
}
}
@end
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
47882 次 |
最近记录: |