【问题标题】:Alignment UIImageView with Aspect Fit使用 Aspect Fit 对齐 UIImageView
【发布时间】:2011-03-17 09:15:16
【问题描述】:

对于我的UIImageView,我选择了Aspect Fit (InterfaceBuilder),但是如何更改垂直对齐方式?

【问题讨论】:

  • 尝试使用 imageview 的 top 和 bottom 属性
  • 设置纵横比时不起作用。
  • GitHub上有一个名为UIImageViewAligned的项目可以完美地做到这一点。

标签: iphone cocoa-touch interface-builder


【解决方案1】:

如果你需要实现aspectFit并去掉空格

不要忘记从情节提要中删除图像视图的宽度限制并享受

class SelfSizedImageView :UIImageView {
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        guard let imageSize = image?.size else {
            return
        }
        
        let viewBounds = bounds
        let imageFactor = imageSize.width / imageSize.height
        let newWidth = viewBounds.height * imageFactor
        
        let myWidthConstraint = self.constraints.first(where: { $0.firstAttribute == .width })
        myWidthConstraint?.constant = min(newWidth, UIScreen.main.bounds.width / 3)
        
        layoutIfNeeded()
    }}

【讨论】:

    【解决方案2】:

    感谢@michael-platt

    要点

    • imageView.contentMode = .scaleAspectFit
    • let width = Layout.height * image.size.width / image.size.height
    • imageView.widthAnchor.constraint(equalToConstant: width).isActive = true

    代码:

    func setupImageView(for image: UIImage) {
        let imageView = UIImageView()
        imageView.backgroundColor = .orange
    
        //Content mode
        imageView.contentMode = .scaleAspectFill
        
        view.addSubview(imageView)
    
        //Constraints
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        imageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
    
        //Feel free to set the height to any value
        imageView.heightAnchor.constraint(equalToConstant: 150).isActive = true
    
        //ImageView width calculation
        let width = Layout.height * image.size.width / image.size.height
        imageView.widthAnchor.constraint(equalToConstant: width).isActive = true
    }
    

    【讨论】:

      【解决方案3】:

      我想出了以下解决方案:

      1. UIImageView内容模式设置为top:imageView.contentMode = .top
      2. 调整图像大小以适应 UIImageView 边界

      要加载和调整图像大小,我使用Kingfisher

      let size = imageView.bounds.size
      let processor = ResizingImageProcessor(referenceSize: size, mode: .aspectFit)
      imageView.kf.setImage(with: URL(string: imageUrl), options: [.processor(processor), .scaleFactor(UIScreen.main.scale)])
      

      【讨论】:

      • 这可行,但图像变得模糊。我通过使用设备屏幕大小和设备缩放因子来修复它,如下所示: let processor = ResizingImageProcessor(referenceSize: view.frame.size, mode: .aspectFit); imageView.kf.setImage(with: url, options:[.processor(processor), .scaleFactor(UIScreen.main.scale)])
      • 太棒了。多谢,伙计。我想左对齐,这行得通
      【解决方案4】:

      这有点棘手,因为如果您已经选择了内容模式 (.scaleAspectFit),则无法设置进一步的对齐规则。

      但这里有一个解决方法:

      首先需要通过计算尺寸来明确调整源图像的大小(如果它在UIImageViewcontentMode = .scaleAspectFit 中)。

      extension UIImage {
      
          func aspectFitImage(inRect rect: CGRect) -> UIImage? {
              let width = self.size.width
              let height = self.size.height
              let aspectWidth = rect.width / width
              let aspectHeight = rect.height / height
              let scaleFactor = aspectWidth > aspectHeight ? rect.size.height / height : rect.size.width / width
      
              UIGraphicsBeginImageContextWithOptions(CGSize(width: width * scaleFactor, height: height * scaleFactor), false, 0.0)
              self.draw(in: CGRect(x: 0.0, y: 0.0, width: width * scaleFactor, height: height * scaleFactor))
      
              defer {
                  UIGraphicsEndImageContext()
              }
      
              return UIGraphicsGetImageFromCurrentImageContext()
          }
      }
      

      然后,您只需通过传递 imageView 的框架在原始图像上调用此函数,并将结果分配给您的 UIImageView.image 属性。另外,请确保在此处(甚至在 Interface Builder 中)设置您的 imageView 所需的 contentMode

      let image = UIImage(named: "MySourceImage")
      imageView.image = image?.aspectFitImage(inRect: imageView.frame)
      imageView.contentMode = .left
      

      【讨论】:

        【解决方案5】:

        要对齐比例以适应图像,请使用自动布局。在 UIImageView 中缩放以适应后的右对齐图像示例:

        1. 创建包含图像的 UIImageView
        2. 为右、上、下、宽添加自动约束
        3. 设置图片:
        myUIImageView.contentMode = .ScaleAspectFit
        myUIImageView.translatesAutoresizingMaskIntoConstraints = false
        myUIImageView.image = UIImage(named:"pizza.png")
        

        您的方面适合缩放的图像现在在 UIImageView 中右对齐

        +----------------------------------+
        |                           [IMAGE]|
        +----------------------------------+
        

        更改约束以在图像视图中以不同方式对齐。

        【讨论】:

        • 这不是很热,如果你使用宽高比,对齐很大程度上取决于图像的实际大小
        【解决方案6】:

        [编辑 - 从 2011 年开始,这段代码有点发霉,除了我合并了@ArtOfWarefare 的模组]

        你不能用 UIImageView 做到这一点。我创建了一个简单的 UIView 子类MyImageView,其中包含一个 UIImageView。代码如下。

        // MyImageView.h
        #import <UIKit/UIKit.h>
        
        @interface MyImageView : UIView {
            UIImageView *_imageView;
        }
        
        @property (nonatomic, assign) UIImage *image;
        
        @end
        

        // MyImageView.m
        
        #import "MyImageView.h"
        
        @implementation MyImageView
        
        @dynamic image;
        
        - (id)initWithCoder:(NSCoder*)coder
        {
            self = [super initWithCoder:coder];
            if (self) {
                self.clipsToBounds = YES;
                _imageView = [[UIImageView alloc] initWithFrame:self.bounds];
                _imageView.contentMode = UIViewContentModeScaleAspectFill;
                [self addSubview:_imageView];
            }
            return self;
        }
        
        - (id)initWithFrame:(CGRect)frame
        {
            self = [super initWithFrame:frame];
            if (self) {
                self.clipsToBounds = YES;
                _imageView = [[UIImageView alloc] initWithFrame:self.bounds];
                _imageView.contentMode = UIViewContentModeScaleAspectFill;
                [self addSubview:_imageView];
            }
            return self;
        }
        
        - (id)initWithImage:(UIImage *)anImage
        {
            self = [self initWithFrame:CGRectZero];
            if (self) {
                _imageView.image = anImage;
                [_imageView sizeToFit];
        
                // initialize frame to be same size as imageView
                self.frame = _imageView.bounds;        
            }
            return self;
        }
        
        // Delete this function if you're using ARC
        - (void)dealloc
        {
            [_imageView release];
            [super dealloc];
        }
        
        - (UIImage *)image
        {
            return _imageView.image;
        }
        
        - (void)setImage:(UIImage *)anImage
        {
            _imageView.image = anImage;
            [self setNeedsLayout];
        }
        
        - (void)layoutSubviews
        {
            if (!self.image) return;
        
            // compute scale factor for imageView
            CGFloat widthScaleFactor = CGRectGetWidth(self.bounds) / self.image.size.width;
            CGFloat heightScaleFactor = CGRectGetHeight(self.bounds) / self.image.size.height;
        
            CGFloat imageViewXOrigin = 0;
            CGFloat imageViewYOrigin = 0;
            CGFloat imageViewWidth;
            CGFloat imageViewHeight;
        
        
            // if image is narrow and tall, scale to width and align vertically to the top
            if (widthScaleFactor > heightScaleFactor) {
                imageViewWidth = self.image.size.width * widthScaleFactor;
                imageViewHeight = self.image.size.height * widthScaleFactor;
            }
        
            // else if image is wide and short, scale to height and align horizontally centered
            else {
                imageViewWidth = self.image.size.width * heightScaleFactor;
                imageViewHeight = self.image.size.height * heightScaleFactor;
                imageViewXOrigin = - (imageViewWidth - CGRectGetWidth(self.bounds))/2;
            }
        
            _imageView.frame = CGRectMake(imageViewXOrigin,
                                          imageViewYOrigin,
                                          imageViewWidth,
                                          imageViewHeight);
        }
        
        - (void)setFrame:(CGRect)frame
        {
            [super setFrame:frame];
            [self setNeedsLayout];
        }
        
        @end
        

        【讨论】:

        • 要完成这项工作,我必须做两件小事:1 - 我实现了initWithCoder(我基本上复制了您的initWithFrame,但用[super initWithFrame:] 替换了[super initWithCoder:])和2 - 我在if (!self.image) return;layoutSubviews 的行中添加,这样如果在调用图像时未分配图像,它就不会因无效几何而崩溃。通过这两个小改动,它的效果非常好。
        • 旁注: 使用 ARC,必须删除 dealloc 方法。
        【解决方案7】:

        感谢开发者,我使用 UIImageViewAligned 来更改图像的对齐方式

        UIImageViewAligned

        【讨论】:

          【解决方案8】:

          尝试设置:

          imageView.contentMode = UIViewContentModeScaleAspectFit;
          imageView.clipsToBounds = YES;
          

          这对我有用。

          【讨论】:

            【解决方案9】:

            如果使用故事板,这可以通过约束来实现...

            首先是具有所需最终帧/约束的 UIView。将 UIImageView 添加到 UIView。将 contentMode 设置为 Aspect Fill。使 UIImageView 框架与图像的比例相同(这样可以避免以后出现任何 Storyboard 警告)。使用标准约束将侧面固定到 UIView。使用标准约束将顶部或底部(取决于您希望对齐的位置)固定到 UIView。最后给 UIImageView 添加一个宽高比约束(确保比例为图片)。

            【讨论】:

            • @Michael Platt,这听起来很混乱,所以这在 iOS 7 中不起作用,因为您需要等效的纵横比,这在 iOS 8+ 中可用?有示例代码吗?
            • 我也实现了这个,它有效。它可能看起来令人困惑,因为该解决方案正在描述自动布局约束设置。对于其他开发人员,我的实现使用了从网络加载的图像,因此我必须根据图像的宽度/高度以编程方式删除并重新添加 UIImageView 纵横比约束。
            • 我使用@MichaelPlatt 解决方案创建了 UIImageView 扩展。 gist.github.com/megimix/d0bbea45bd3e1e4d615fbd5c30b54da7
            【解决方案10】:

            我知道这是一个旧线程,但我想我会分享我所做的,以便在 Interface Builder 中轻松地将剪切区域从图像视图的顶部更改为底部,以防有人遇到与我相同的问题.我有一个 UIImageView 填充了我的 ViewController 的视图,并试图使顶部保持不变,与设备屏幕的大小无关。

            1. 我应用了 Retina 4 外形尺寸(Editor->Apply Retina 4 Form Factor)。

            2. 我固定了高度和宽度。

            现在,当屏幕改变大小时,UIImageView 实际上是相同的大小,视图控制器只是裁剪掉屏幕外的内容。帧原点保持在 0,0,因此图像的底部和右侧被剪裁,而不是顶部。

            希望这会有所帮助。

            【讨论】:

              【解决方案11】:

              您可以通过先缩放然后调整大小来实现。 这里要提到的是,我受身高的制约。我的意思是,无论宽度如何,我都必须拥有 34px 高的图像。

              因此,获取实际内容高度与视图高度(34 px)之间的比率,然后也缩放宽度。

              我是这样做的:

              CGSize size = [imageView sizeThatFits:imageView.frame.size];
              
              CGSize actualSize;
              actualSize.height = imageView.frame.size.height;
              actualSize.width = size.width / (1.0 * (size.height / imageView.frame.size.height));
              
              CGRect frame = imageView.frame;
              frame.size = actualSize;
              [imageView setFrame:frame];
              

              希望这会有所帮助。

              【讨论】:

                【解决方案12】:

                我通过继承 UIImageView 并覆盖 setImage: 方法解决了这个问题。子类将首先存储它的原始值和大小,以便它可以使用原始设置大小作为边界框。

                我将内容模式设置为 UIViewContentModeAspectFit。在 setImage 内部:我抓取了图像的宽高比,然后调整了图像视图的大小以适应与图像相同的比例。调整大小后,我调整了我的框架属性以将图像视图设置在与之前相同的位置,然后我调用了超级 setImage:。

                这会导致图像视图的框架被调整以完全适合图像,因此方面适合工作,并且图像视图框架属性在将图像视图放置在应该获得相同效果的位置方面发挥了重要作用。

                这是我使用的一些代码:

                首先,我发现它总体上非常有用,它是 UIView 上的一个类别,它可以通过左、右、上、下、宽度、高度等属性轻松设置视图上的框架属性。

                UIImageView+FrameAdditions

                @interface UIView (FrameAdditions)
                
                @property CGFloat left, right, top, bottom, width, height;
                @property CGPoint origin;
                
                @end
                
                @implementation UIView (FrameAdditions)
                
                - (CGFloat)left {
                    return self.frame.origin.x;
                }
                
                - (void)setLeft:(CGFloat)left {
                    self.frame = CGRectMake(left, self.frame.origin.y, self.frame.size.width, self.frame.size.height);
                }
                
                - (CGFloat)right {
                    return self.frame.origin.x + self.frame.size.width;
                }
                
                - (void)setRight:(CGFloat)right {
                    self.frame = CGRectMake(right - self.frame.size.width, self.frame.origin.y, self.frame.size.width, self.frame.size.height);
                }
                
                - (CGFloat)top {
                    return self.frame.origin.y;
                }
                
                - (void)setTop:(CGFloat)top {
                    self.frame = CGRectMake(self.frame.origin.x, top, self.frame.size.width, self.frame.size.height);
                }
                
                - (CGFloat)bottom {
                    return self.frame.origin.y + self.frame.size.height;
                }
                
                - (void)setBottom:(CGFloat)bottom {
                    self.frame = CGRectMake(self.frame.origin.x, bottom - self.frame.size.height, self.frame.size.width, self.frame.size.height);
                }
                
                - (CGFloat)width {
                    return self.frame.size.width;
                }
                
                - (void)setWidth:(CGFloat)width {
                    self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, width, self.frame.size.height);
                }
                
                - (CGFloat)height {
                    return self.frame.size.height;
                }
                
                - (void)setHeight:(CGFloat)height {
                    self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, height);
                }
                
                - (CGPoint)origin {
                    return self.frame.origin;
                }
                
                - (void)setOrigin:(CGPoint)origin {
                    self.frame = CGRectMake(origin.x, origin.y, self.frame.size.width, self.frame.size.height);
                }
                
                @end
                

                这是 UIImageView 的子类。它没有经过全面测试,但应该可以理解。这可以扩展为设置您自己的新对齐模式。

                BottomCenteredImageView

                @interface BottomCenteredImageView : UIImageView
                
                @end
                
                
                @interface BottomCenteredImageView() {
                    CGFloat originalLeft;
                    CGFloat originalBottom;
                    CGFloat originalHeight;
                    CGFloat originalWidth;
                }
                
                @end
                
                @implementation BottomCenteredImageView
                
                - (id)initWithFrame:(CGRect)frame {
                    self = [super initWithFrame:frame];
                    if(self) {
                        [self initialize];
                    }
                    return self;
                }
                
                - (void)awakeFromNib {
                    [self initialize];
                }
                
                - (void)initialize {
                    originalLeft = self.frame.origin.x;
                    originalHeight = CGRectGetHeight(self.frame);
                    originalWidth = CGRectGetWidth(self.frame);
                    originalBottom = self.frame.origin.y + originalHeight;
                }
                
                - (void)setImage:(UIImage *)image {
                    if(image) {
                        self.width = originalWidth;
                        self.height = originalHeight;
                        self.left = originalLeft;
                        self.bottom = originalBottom;
                
                        float myWidthToHeightRatio = originalWidth/originalHeight;
                        float imageWidthToHeightRatio = image.size.width/image.size.height;
                        if(myWidthToHeightRatio >= imageWidthToHeightRatio) {
                            // Calculate my new width
                            CGFloat newWidth = self.height * imageWidthToHeightRatio;
                            self.width = newWidth;
                            self.left = originalLeft + (originalWidth - self.width)/2;
                            self.bottom = originalBottom;
                        } else {
                            // Calculate my new height
                            CGFloat newHeight = self.width / imageWidthToHeightRatio;
                            self.height = newHeight;
                            self.bottom = originalBottom;
                        }
                        self.contentMode = UIViewContentModeScaleAspectFit;
                        [super setImage:image];
                    } else {
                        [super setImage:image];
                    }
                }
                
                @end
                

                【讨论】:

                • 不要在 VC 中使用 UIImageView,而是使用 BottomCenteredImageView。
                • 这对我不起作用......它改变了我的视图的纵横比以匹配我不想要的图像的纵横比...... XJones 提供的答案很好用我在他的答案下方的 cmets 中注意到了一些变化。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2018-06-06
                • 2015-07-29
                • 1970-01-01
                • 1970-01-01
                • 2016-12-30
                • 2011-12-26
                • 1970-01-01
                相关资源
                最近更新 更多