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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:47:35  来源:igfitidea点击:

UIImage aspect fit and align to top

ioscocoauiimageviewaspect-fit

提问by Hymansonkr

It looks like aspect fitaligns the image to the bottom of the frame by default. Is there a way to overridethe alignment while keeping aspect fitintact?

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

In short, you cannot do this with a UIImageView.

简而言之,您不能使用UIImageView.

One solution is to subclass a UIViewcontaining an UIImageViewand change its frame according to image size. For example, you can find one version here.

一种解决方案是将UIView包含a的子类化UIImageView并根据图像大小更改其框架。例如,您可以在此处找到一个版本。

回答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

你可以在这里查看:https: //github.com/LucasssD/LDAlignmentImageView

回答by ?ukasz Giera?towski

  1. Add the Aspect Ratio constraint with your image proportions.
  2. Do not pin UIImageView to bottom.
  3. If you want to change the UIImage dynamically remember to update aspect ratio constraint.
  1. 使用您的图像比例添加纵横比约束。
  2. 不要将 UIImageView 固定到底部。
  3. 如果要动态更改 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 imagevar.

如果您能够子类化UIImageView,那么您只需覆盖imagevar。

override var image: UIImage? {
    didSet {
        self.sizeToFit()
    }
}

In Objective-C you can do the same thing by overriding the setter.

在 Objective-C 中,你可以通过覆盖 setter 来做同样的事情。