Выравнивание UIImageView с Aspect Fit
Для моего UIImageView я выбираю Aspect Fit (InterfaceBuilder), но как я могу изменить вертикальное выравнивание?
12 ответов
[РЕДАКТИРОВАТЬ - этот код немного плесень с 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
При использовании раскадровки это может быть достигнуто с ограничениями...
Во-первых, UIView с желаемым финальным кадром / ограничениями. Добавьте UIImageView к UIView. Установите для contentMode Aspect Fill. Сделайте для кадра UIImageView такое же соотношение, как и для изображения (это позволит избежать любых предупреждений раскадровки позже). Прикрепите стороны к UIView, используя стандартные ограничения. Прикрепите верхний ИЛИ нижний (в зависимости от того, где вы хотите выровнять) к UIView, используя стандартные ограничения. Наконец добавьте ограничение соотношения сторон в UIImageView (убедитесь, что соотношение в качестве изображения).
Это немного сложнее, поскольку нет возможности установить дополнительные правила выравнивания, если вы уже выбрали режим содержимого (.scaleAspectFit
).
Но вот обходной путь к этому:
Сначала нужно явно изменить размер исходного изображения, рассчитав размеры (если бы UIImageView
с contentMode = .scaleAspectFit
).
extension UIImage {
func aspectFitImage(inRect rect: CGRect) -> UIImage? {
let width = self.size.width
let height = self.size.height
let scaleFactor = width > height ? 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
имущество. Также убедитесь, что вы установили желаемый imageView contentMode
здесь (или даже в Интерфейсном Разработчике)!
let image = UIImage(named: "MySourceImage")
imageView.image = image?.aspectFitImage(inRect: imageView.frame)
imageView.contentMode = .left
Попробуйте установить:
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
Это сработало для меня.
Я использовал UIImageViewAligned для изменения выравнивания изображения благодаря разработчику
Я знаю, что это старая ветка, но я решил поделиться тем, что сделал, чтобы легко изменить обрезанную область сверху вниз в представлении изображений в Интерфейсном Разработчике, на случай, если у кого-то возникнет та же проблема, что и у меня. У меня был UIImageView, который заполнил View моего ViewController, и я пытался сделать верхний слой таким же, независимо от размера экрана устройства.
Я применил форм-фактор Retina 4 (редактор-> Применить форм-фактор Retina 4).
Я прикрепил высоту и ширину.
Теперь, когда экран меняет размер, UIImageView на самом деле имеет тот же размер, а контроллер представления просто обрезает то, что находится за пределами экрана. Начало кадра остается равным 0,0, поэтому нижняя и правая части изображения обрезаются, а не верхняя.
Надеюсь это поможет.
Я пришел к следующему решению:
- Задавать
UIImageView
режим содержания дляtop
:imageView.contentMode = .top
- Изменение размера изображения в соответствии с границами UIImageView
Для загрузки и изменения размера изображения я использую Kingfisher:
let size = imageView.bounds.size
let processor = ResizingImageProcessor(referenceSize: size, mode: .aspectFit)
imageView.kf.setImage(with: URL(string: imageUrl), options: [.processor(processor)])
Если вам нужно достичь aspectFit и избавиться от пустых мест
Не забудьте убрать ограничение ширины вашего изображения из раскадровки и наслаждайтесь
Класс 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()
}}
Вы можете сделать это сначала с помощью масштабирования, а затем изменения размера. Здесь нужно упомянуть, что я был обусловлен ростом. Я имею в виду, я должен был иметь изображение высотой 34px и независимо от его ширины.
Таким образом, получите соотношение между фактической высотой содержимого и высотой представления ( 34 пикселя), а затем масштабируйте также ширину.
Вот как я это сделал:
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];
Надеюсь это поможет.
Я решил это путем создания подкласса UIImageView и переопределения метода setImage:. Подкласс сначала будет хранить свои исходные значения для источника и размера, чтобы он мог использовать исходный размер набора в качестве ограничительной рамки.
Я установил режим содержимого в UIViewContentModeAspectFit. Внутри setImage: я взял соотношение ширины и высоты изображения, а затем изменил размер изображения, чтобы оно соответствовало тому же отношению, что и изображение. После изменения размера я настроил свойства своего кадра, чтобы установить вид изображения на то же место, что и раньше, а затем вызвал super setImage:.
Это приводит к тому, что представление изображения настраивается так, чтобы точно соответствовать изображению, поэтому аспектное подгонка работает, и свойства рамки представления изображения делают большую работу, помещая представление изображения туда, где и должен быть тот же эффект.
Вот код, который я использовал:
Прежде всего, и я нахожу это довольно полезным в целом, это категория в UIView, которая позволяет легко устанавливать свойства фрейма в представлении с помощью таких свойств, как left, right, top, bottom, width, height и т. Д.
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
Кредит @ michael-platt
Ключевые моменты
-
imageView.contentMode = .scaleAspectFill
-
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor).isActive = true
Код:
func setupImageView() {
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.widthAnchor.constraint(equalTo: imageView.heightAnchor).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
}
Чтобы выровнять масштабируемое изображение по размеру, используйте автоматический макет. Пример выровненного по правому краю изображения после масштабирования по размеру в UIImageView:
- Создайте UIImageView, который содержит изображение
- Добавить авто ограничения для правого, верхнего, нижнего, ширины
- Установите изображение:
myUIImageView.contentMode = .ScaleAspectFit myUIImageView.translatesAutoresizingMaskIntoConstraints = false myUIImageView.image = UIImage(named:"pizza.png")
Ваше масштабированное изображение по размеру теперь выровнено по правому краю в UIImageView
+----------------------------------+
| [IMAGE]|
+----------------------------------+
Измените ограничения, чтобы выровнять по-разному в пределах изображения.