Alignment UIImageView với Aspect Fit


79

cho UIImageView của tôi, tôi chọn Aspect Fit (InterfaceBuilder) nhưng làm cách nào để thay đổi căn chỉnh dọc?


1
thử với thuộc tính trên và dưới của
imageview

Không hoạt động khi bạn đã đặt Aspect Fit.
Ethan Allen

5
Có một dự án trên GitHub được gọi là UIImageViewAligned thực hiện điều này một cách hoàn hảo.
Daniel Storm

Câu trả lời:


40

[CHỈNH SỬA - mã này hơi ẩm mốc từ năm 2011 và tất cả, ngoại trừ tôi đã kết hợp các mod của @ ArtOfWarefare]

Bạn không thể làm điều này với w / UIImageView. Tôi đã tạo một lớp con UIView đơn giản MyImageViewcó chứa UIImageView. Mã bên dưới.

// 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

3
Hai điều nhỏ tôi phải làm để làm cho công việc này: 1 - Tôi đã triển khai initWithCoder(về cơ bản tôi đã sao chép của bạn initWithFramenhưng thay thế [super initWithFrame:]bằng [super initWithCoder:]) và 2 - Tôi thêm vào một dòng if (!self.image) return;để layoutSubviewsnó không bị lỗi với hình không hợp lệ nếu một hình ảnh không phải là ' t được chỉ định khi nó được gọi. Với hai thay đổi nhỏ này, nó hoạt động đáng kinh ngạc.
ArtOfWarfare

ghi chú bên lề: với ARC, deallocphương thức phải được loại bỏ.
Raptor

35

Nếu sử dụng Bảng phân cảnh, điều này có thể đạt được với các ràng buộc ...

Đầu tiên là một UIView với khung / ràng buộc cuối cùng mong muốn. Thêm UIImageView vào UIView. Đặt contentMode thành Aspect Fill. Đặt khung UIImageView có cùng tỷ lệ với hình ảnh (điều này tránh mọi cảnh báo về Storyboard sau này). Ghim các bên vào UIView bằng cách sử dụng các ràng buộc tiêu chuẩn. Ghim phần trên cùng HOẶC phía dưới (tùy thuộc vào vị trí bạn muốn căn chỉnh) vào UIView bằng cách sử dụng các ràng buộc tiêu chuẩn. Cuối cùng thêm ràng buộc tỷ lệ khung hình vào UIImageView (đảm bảo tỷ lệ như hình ảnh).


@Michael Platt, Điều này nghe có vẻ khó hiểu, vì vậy điều này không thể hoạt động trong iOS 7, vì bạn yêu cầu tỷ lệ khung hình tương đương, có sẵn trong iOS 8+? Bạn có mã ví dụ nào không?
Özgür

2
Tôi cũng đã thực hiện điều này, nó hoạt động. Nó có vẻ khó hiểu vì giải pháp đang mô tả thiết lập ràng buộc bố cục tự động. Đối với các nhà phát triển khác, việc triển khai của tôi sử dụng hình ảnh được tải từ web, vì vậy tôi phải xóa và thêm lại ràng buộc tỷ lệ khung hình UIImageView theo lập trình dựa trên chiều rộng / chiều cao của hình ảnh.
Michael DePhillips

3
Tôi đã tạo tiện ích mở rộng UIImageView bằng giải pháp @MichaelPlatt. gist.github.com/megimix/d0bbea45bd3e1e4d615fbd5c30b54da7
megimix

15

Điều này hơi phức tạp vì không có tùy chọn để đặt thêm các quy tắc căn chỉnh nếu bạn đã chọn chế độ nội dung ( .scaleAspectFit).

Nhưng đây là một giải pháp cho điều này:

Trước tiên, cần thay đổi kích thước hình ảnh nguồn của bạn một cách rõ ràng bằng cách tính toán các kích thước (nếu nó UIImageViewbằng với contentMode = .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()
    }
}

Sau đó, bạn chỉ cần gọi hàm này trên hình ảnh gốc của mình bằng cách chuyển khung của imageView và gán kết quả cho thuộc tính của bạn UIImageView.image. Ngoài ra, hãy đảm bảo bạn đặt imageView mong muốn contentModeở đây ( hoặc thậm chí trong Trình tạo giao diện )!

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

4

Thử cài đặt:

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

Điều này đã làm việc cho tôi.



2

Tôi biết đây là một chủ đề cũ, nhưng tôi nghĩ tôi sẽ chia sẻ những gì tôi đã làm để dễ dàng thay đổi vùng bị cắt từ trên xuống dưới của chế độ xem hình ảnh trong Trình tạo giao diện, trong trường hợp bất kỳ ai gặp vấn đề tương tự như tôi đã làm. Tôi có một UIImageView lấp đầy Khung nhìn của ViewController và đang cố gắng giữ nguyên phần trên cùng, không phụ thuộc vào kích thước màn hình của thiết bị.

  1. Tôi đã áp dụng hệ số hình thức 4 võng mạc (Editor-> Áp dụng hệ số hình thức 4 võng mạc).

  2. Tôi đã ghim chiều cao và chiều rộng.

Bây giờ, khi màn hình thay đổi kích thước, UIImageView thực sự có cùng kích thước và bộ điều khiển chế độ xem chỉ cắt những gì hiển thị ra khỏi màn hình. Gốc khung vẫn ở 0,0, vì vậy phần dưới và bên phải của hình ảnh được cắt bớt, không phải phần trên cùng.

Hi vọng điêu nay co ich.


1

Bạn có thể làm điều đó bằng cách mở rộng quy mô đầu tiên và sau đó thay đổi kích thước. Điều cần đề cập ở đây là tôi đã bị quy định bởi chiều cao. Ý tôi là, tôi phải có hình ảnh cao 34px và bất kể chiều rộng như thế nào.

Vì vậy, hãy lấy tỷ lệ giữa chiều cao nội dung thực tế và chiều cao của chế độ xem (34 px) và sau đó cũng chia tỷ lệ chiều rộng.

Đây là cách tôi đã làm điều đó:

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];

Hi vọng điêu nay co ich.


1

Tôi đã đưa ra giải pháp sau:

  1. Đặt UIImageViewchế độ nội dung thành top:imageView.contentMode = .top
  2. Thay đổi kích thước hình ảnh để phù hợp với giới hạn của UIImageView

Để tải và thay đổi kích thước hình ảnh, tôi sử dụng 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)])

Điều này hoạt động nhưng hình ảnh bị mờ. Tôi đã sửa nó bằng cách sử dụng kích thước màn hình thiết bị và hệ số tỷ lệ thiết bị như sau: let processor = ResizingImageProcessor (referenceSize: view.frame.size, mode: .aspectFit); imageView.kf.setImage (với: url, các tùy chọn: [. processor (bộ xử lý), .scaleFactor (UIScreen.main.scale)])
Alexander Maslew

Tuyệt vời. Cảm ơn anh bạn. Tôi muốn căn trái và điều này đã thành công
Kunal Gupta

0

Tôi đã giải quyết vấn đề này bằng cách phân lớp UIImageView và ghi đè phương thức setImage:. Trước tiên, lớp con sẽ lưu trữ các giá trị ban đầu cho nguồn gốc và kích thước để nó có thể sử dụng kích thước đặt ban đầu làm hộp giới hạn.

Tôi đặt chế độ nội dung thành UIViewContentModeAspectFit. Inside of setImage: Tôi chọn tỷ lệ chiều rộng và chiều cao của hình ảnh và sau đó thay đổi kích thước chế độ xem hình ảnh để phù hợp với cùng tỷ lệ với hình ảnh. Sau khi thay đổi kích thước, tôi đã điều chỉnh các thuộc tính khung của mình để đặt chế độ xem hình ảnh ở cùng vị trí trước đó và sau đó tôi gọi là super setImage :.

Điều này dẫn đến chế độ xem hình ảnh, khung của ai được điều chỉnh để vừa với hình ảnh một cách chính xác, do đó tính năng phù hợp với khung hình hoạt động và các thuộc tính khung của chế độ xem hình ảnh đang làm việc nặng nhọc trong việc đặt chế độ xem hình ảnh ở vị trí cần thiết để có được hiệu ứng tương tự.

Đây là một số mã mà tôi đã sử dụng:

Đầu tiên và tôi thấy nó khá hữu ích nói chung, là một danh mục trên UIView giúp bạn dễ dàng thiết lập các thuộc tính khung trên một chế độ xem thông qua các thuộc tính như trái, phải, trên, dưới, chiều rộng, chiều cao, v.v.

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

Đây là lớp con của UIImageView. Nó không được thử nghiệm đầy đủ, nhưng sẽ có ý tưởng xuyên suốt. Điều này có thể được mở rộng để đặt các chế độ mới của riêng bạn để căn chỉnh.

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

Thay vì sử dụng UIImageView trong VC của bạn, hãy sử dụng BottomCenteredImageView.
slmke

Điều này không hiệu quả với tôi ... nó đã thay đổi tỷ lệ khung hình của chế độ xem của tôi để phù hợp với tỷ lệ khung hình của hình ảnh không phải như những gì tôi muốn ... Câu trả lời mà XJones cung cấp đã hoạt động tuyệt vời với một vài thay đổi mà tôi đã ghi nhận trong bình luận bên dưới câu trả lời của mình.
ArtOfWarfare

0

Nếu bạn cần đạt được khía cạnh và loại bỏ các khoảng trống

Đừng quên xóa giới hạn chiều rộng của chế độ xem hình ảnh khỏi bảng phân cảnh và tận hưởng

class SelfSizeImageView: 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()
}}

-6

Để căn chỉnh hình ảnh theo tỷ lệ để vừa vặn, hãy sử dụng bố cục tự động. Ví dụ về hình ảnh căn phải sau khi điều chỉnh tỷ lệ để vừa vặn trong UIImageView:

  1. Tạo UIImageView chứa hình ảnh
  2. Thêm các ràng buộc tự động cho bên phải, trên cùng, dưới cùng, chiều rộng
  3. Đặt hình ảnh:
myUIImageView.contentMode = .ScaleAspectFit
myUIImageView.translatesAutoresizingMaskIntoConstraints = false
myUIImageView.image = UIImage(named:"pizza.png")

Hình ảnh được chia tỷ lệ phù hợp với các khía cạnh của bạn hiện đã được căn chỉnh ngay trong UIImageView

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

Thay đổi các ràng buộc để căn chỉnh khác nhau trong chế độ xem hình ảnh.


Đây không phải là nóng nó hoạt động, nếu bạn đang sử dụng khía cạnh phù hợp, sự liên kết rất nhiều phụ thuộc vào kích thước thực tế của hình ảnh
Abhishek Maurya
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.