ios UIImage 方面适合并对齐到顶部
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11039943/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIImage aspect fit and align to top
提问by Hymansonkr
It looks like aspect fit
aligns the image to the bottom of the frame by default. Is there a way to overridethe alignment while keeping aspect fit
intact?
aspect fit
默认情况下,它看起来像将图像对齐到框架的底部。有没有办法在保持完整的同时覆盖对齐aspect fit
?
** EDIT **
** 编辑 **
This question predates auto layout. In fact, auto layout was being revealed in WWDC 2012 the same week this question was asked
这个问题早于自动布局。事实上,在 WWDC 2012 的同一周,这个问题被问到了自动布局
回答by Mundi
回答by Werner Altewischer
The way to do this is to modify the contentsRect of the UIImageView layer. The following code from my project (sub class of UIImageView) assumes scaleToFill and offsets the image such that it aligns top, bottom, left or right instead of the default center alignment. For aspectFit is would be a similar solution.
这样做的方法是修改 UIImageView 层的 contentsRect 。我的项目(UIImageView 的子类)中的以下代码假定 scaleToFill 并偏移图像,使其顶部、底部、左侧或右侧对齐,而不是默认的居中对齐方式。对于 aspectFit 将是一个类似的解决方案。
typedef NS_OPTIONS(NSUInteger, AHTImageAlignmentMode) {
AHTImageAlignmentModeCenter = 0,
AHTImageAlignmentModeLeft = 1 << 0,
AHTImageAlignmentModeRight = 1 << 1,
AHTImageAlignmentModeTop = 1 << 2,
AHTImageAlignmentModeBottom = 1 << 3,
AHTImageAlignmentModeDefault = AHTImageAlignmentModeCenter,
};
- (void)updateImageViewContentsRect {
CGRect imageViewContentsRect = CGRectMake(0, 0, 1, 1);
if (self.image.size.height > 0 && self.bounds.size.height > 0) {
CGRect imageViewBounds = self.bounds;
CGSize imageSize = self.image.size;
CGFloat imageViewFactor = imageViewBounds.size.width / imageViewBounds.size.height;
CGFloat imageFactor = imageSize.width / imageSize.height;
if (imageFactor > imageViewFactor) {
//Image is wider than the view, so height will match
CGFloat scaledImageWidth = imageViewBounds.size.height * imageFactor;
CGFloat xOffset = 0.0;
if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeLeft)) {
xOffset = -(scaledImageWidth - imageViewBounds.size.width) / 2;
} else if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeRight)) {
xOffset = (scaledImageWidth - imageViewBounds.size.width) / 2;
}
imageViewContentsRect.origin.x = (xOffset / scaledImageWidth);
} else if (imageFactor < imageViewFactor) {
CGFloat scaledImageHeight = imageViewBounds.size.width / imageFactor;
CGFloat yOffset = 0.0;
if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeTop)) {
yOffset = -(scaledImageHeight - imageViewBounds.size.height) / 2;
} else if (BM_CONTAINS_BIT(self.alignmentMode, AHTImageAlignmentModeBottom)) {
yOffset = (scaledImageHeight - imageViewBounds.size.height) / 2;
}
imageViewContentsRect.origin.y = (yOffset / scaledImageHeight);
}
}
self.layer.contentsRect = imageViewContentsRect;
}
Swift version
迅捷版
class AlignmentImageView: UIImageView {
enum HorizontalAlignment {
case left, center, right
}
enum VerticalAlignment {
case top, center, bottom
}
// MARK: Properties
var horizontalAlignment: HorizontalAlignment = .center
var verticalAlignment: VerticalAlignment = .center
// MARK: Overrides
override var image: UIImage? {
didSet {
updateContentsRect()
}
}
override func layoutSubviews() {
super.layoutSubviews()
updateContentsRect()
}
// MARK: Content layout
private func updateContentsRect() {
var contentsRect = CGRect(origin: .zero, size: CGSize(width: 1, height: 1))
guard let imageSize = image?.size else {
layer.contentsRect = contentsRect
return
}
let viewBounds = bounds
let imageViewFactor = viewBounds.size.width / viewBounds.size.height
let imageFactor = imageSize.width / imageSize.height
if imageFactor > imageViewFactor {
// Image is wider than the view, so height will match
let scaledImageWidth = viewBounds.size.height * imageFactor
var xOffset: CGFloat = 0.0
if case .left = horizontalAlignment {
xOffset = -(scaledImageWidth - viewBounds.size.width) / 2
}
else if case .right = horizontalAlignment {
xOffset = (scaledImageWidth - viewBounds.size.width) / 2
}
contentsRect.origin.x = xOffset / scaledImageWidth
}
else {
let scaledImageHeight = viewBounds.size.width / imageFactor
var yOffset: CGFloat = 0.0
if case .top = verticalAlignment {
yOffset = -(scaledImageHeight - viewBounds.size.height) / 2
}
else if case .bottom = verticalAlignment {
yOffset = (scaledImageHeight - viewBounds.size.height) / 2
}
contentsRect.origin.y = yOffset / scaledImageHeight
}
layer.contentsRect = contentsRect
}
}
回答by protspace
Set the UIImageView
's bottom layout constraint priority to lowest (i.e. 250) and it will handle it for you.
将UIImageView
的底部布局约束优先级设置为最低(即 250),它将为您处理。
回答by no_ripcord
this will make the image fill the width and occupy only the height it needs to fit the image (widthly talking)
这将使图像填充宽度并仅占据适合图像所需的高度(宽泛地说)
swift 4.2:
快速 4.2:
let image = UIImage(named: "my_image")!
let ratio = image.size.width / image.size.height
cardImageView.widthAnchor
.constraint(equalTo: cardImageView.heightAnchor, multiplier: ratio).isActive = true
回答by ?ukasz Duda
I had similar problem. Simplest way was to create own subclass of UIImageView. I add for subclass 3 properties so now it can be use easly without knowing internal implementation:
我有类似的问题。最简单的方法是创建自己的 UIImageView 子类。我添加了子类 3 属性,因此现在可以在不知道内部实现的情况下轻松使用它:
@property (nonatomic) LDImageVerticalAlignment imageVerticalAlignment;
@property (nonatomic) LDImageHorizontalAlignment imageHorizontalAlignment;
@property (nonatomic) LDImageContentMode imageContentMode;
You can check it here: https://github.com/LucasssD/LDAlignmentImageView
回答by ?ukasz Giera?towski
- Add the Aspect Ratio constraint with your image proportions.
- Do not pin UIImageView to bottom.
- If you want to change the UIImage dynamically remember to update aspect ratio constraint.
- 使用您的图像比例添加纵横比约束。
- 不要将 UIImageView 固定到底部。
- 如果要动态更改 UIImage,请记住更新宽高比约束。
回答by David T
I solved this natively in Interface Builder by setting a constraint on the height of the UIImageView, since the image would always be 'pushed' up when the image was larger than the screen size.
我通过在 UIImageView 的高度上设置约束,在 Interface Builder 中本地解决了这个问题,因为当图像大于屏幕尺寸时,图像总是会被“向上推”。
More specifically, I set the UIImageView to be the same height as the View it is in (via height constraint), then positioned the UIImageView with spacing constraints in IB. This results in the UIImageView having an 'Aspect Fit' which still respects the top spacing constraint I set in IB.
更具体地说,我将 UIImageView 设置为与其所在视图相同的高度(通过高度约束),然后在 IB 中使用间距约束定位 UIImageView。这导致 UIImageView 具有“Aspect Fit”,它仍然遵守我在 IB 中设置的顶部间距约束。
回答by Dan Rosenstark
If you are able to subclass UIImageView
, then you can just override the image
var.
如果您能够子类化UIImageView
,那么您只需覆盖image
var。
override var image: UIImage? {
didSet {
self.sizeToFit()
}
}
In Objective-C you can do the same thing by overriding the setter.
在 Objective-C 中,你可以通过覆盖 setter 来做同样的事情。