Аспект UIImage подходит и выравнивается
Похоже, что aspect fit
по умолчанию выравнивает изображение в нижней части рамки. Есть ли способ переопределить выравнивание, сохраняя aspect fit
неповрежденным?
** РЕДАКТИРОВАТЬ **
Этот вопрос предшествует автомаршруту. Фактически, автоматическая раскладка показывалась в WWDC 2012 на той же неделе, когда этот вопрос задавали
Ответы
Ответ 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
- Добавьте ограничение соотношения сторон с пропорциями изображения.
- Не прикрепляйте UIImageView к основанию.
- Если вы хотите динамически изменять 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 вы можете сделать то же самое, переопределив сеттер.