Подтвердить что ты не робот

Аспект UIImage подходит и выравнивается

Похоже, что aspect fit по умолчанию выравнивает изображение в нижней части рамки. Есть ли способ переопределить выравнивание, сохраняя aspect fit неповрежденным?

** РЕДАКТИРОВАТЬ **

Этот вопрос предшествует автомаршруту. Фактически, автоматическая раскладка показывалась в WWDC 2012 на той же неделе, когда этот вопрос задавали

4b9b3361

Ответ 1

Короче говоря, вы не можете сделать это с помощью UIImageView.

Одним из решений является подкласс a UIView, содержащий UIImageView, и изменение его кадра в соответствии с размером изображения. Например, вы можете найти одну версию здесь.

Ответ 2

Способ сделать это - изменить contentRect слоя UIImageView. Следующий код из моего проекта (подкласс 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 версия

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
    }

}

Ответ 3

Просто установите приоритет ограничения нижней рамки изображения для нижнего (т.е. 250), и он выполнит работу

Ответ 4

У меня была аналогичная проблема. Самый простой способ - создать собственный подкласс UIImageView. Я добавляю для свойств подкласса 3, поэтому теперь его можно использовать без знания внутренней реализации:

@property (nonatomic) LDImageVerticalAlignment imageVerticalAlignment;
@property (nonatomic) LDImageHorizontalAlignment imageHorizontalAlignment;
@property (nonatomic) LDImageContentMode imageContentMode;

Вы можете проверить это здесь: https://github.com/LucasssD/LDAlignmentImageView

Ответ 5

  1. Добавьте ограничение соотношения сторон с пропорциями изображения.
  2. Не прикрепляйте UIImageView к основанию.
  3. Если вы хотите динамически изменять UIImage, не забудьте обновить ограничение соотношения сторон.

Ответ 6

Я решил это изначально в Interface Builder, установив ограничение на высоту UIImageView, так как изображение всегда будет "выдвинуто", когда изображение будет больше размера экрана.

В частности, я установил UIImageView на ту же высоту, что и View, в которой он находится (через ограничение по высоте), затем позиционирует UIImageView с ограничениями расстояния в IB. Это приводит к тому, что UIImageView имеет "Aspect Fit", который по-прежнему соблюдает ограничение верхнего расстояния, установленное в IB.

Ответ 7

это заставит изображение заполнять ширину и занимать только ту высоту, которая ему нужна, чтобы соответствовать изображению (широко говоря)

Swift 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

Ответ 8

Если вы можете подклассом UIImageView, вы можете просто переопределить image var.

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

В Objective-C вы можете сделать то же самое, переопределив сеттер.