iphone - objective - Alineación UIImageView con ajuste de aspecto
uiimageview set image swift (9)
Esto es un poco complicado ya que no hay opción para establecer más reglas de alineación si ya seleccionó un modo de contenido ( .scaleAspectFit
).
Pero aquí hay una solución a esto:
Primero necesita cambiar el tamaño de su imagen de origen de forma explícita calculando las dimensiones (si estuviera en un UIImageView
con 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()
}
}
Luego, simplemente necesita llamar a esta función en su imagen original pasando el marco de su imageView y asigne el resultado a su propiedad UIImageView.image
. ¡Asegúrate también de configurar el modo de contentMode
deseado de tu imageView aquí ( o incluso en el Interface Builder )!
let image = UIImage(named: "MySourceImage")
imageView.image = image?.aspectFitImage(inRect: imageView.frame)
imageView.contentMode = .left
para mi UIImageView elijo Aspect Fit (InterfaceBuilder) pero ¿cómo puedo cambiar la alineación vertical?
Intenta configurar:
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
Esto funcionó para mí.
Lo resolví subclasificando UIImageView y reemplazando el método setImage: La subclase primero almacenaría sus valores originales para el origen y el tamaño, por lo que podría usar el tamaño del conjunto original como un cuadro delimitador.
Establecí el modo de contenido en UIViewContentModeAspectFit. Dentro de setImage: Agarré la relación ancho / alto de la imagen y luego redimensioné la vista de la imagen para ajustarla a la misma relación que la imagen. Después del cambio de tamaño, ajusté las propiedades de mi marco para establecer la vista de la imagen en el mismo lugar que estaba antes, y luego llamé al súper setImage :.
Esto da como resultado una vista de imagen cuyo marco se ajusta para ajustarse exactamente a la imagen, por lo que el ajuste de aspecto funciona y las propiedades del marco de vista de imagen hacen un trabajo pesado al colocar la vista de la imagen donde debería para obtener el mismo efecto.
Aquí hay un código que utilicé:
Primero, y lo encuentro bastante útil en general, es una categoría en UIView que hace que sea fácil establecer propiedades de marco en una vista mediante propiedades como izquierda, derecha, arriba, abajo, ancho, alto, etc.
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
Esta es la subclase de UIImageView. No está completamente probado, pero debe transmitir la idea. Esto podría expandirse para establecer sus propios modos de alineación.
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
Para alinear una imagen de escala para ajustar, use la distribución automática. Ejemplo de imagen alineada a la derecha después de escalar para ajustar en UIImageView:
- Crear UIImageView que contiene la imagen
- Agregue restricciones automáticas para derecha, arriba, abajo, ancho
- Establecer la imagen:
myUIImageView.contentMode = .ScaleAspectFit myUIImageView.translatesAutoresizingMaskIntoConstraints = false myUIImageView.image = UIImage(named:"pizza.png")
La imagen escalada de su aspecto ahora está alineada a la derecha en el UIImageView
+----------------------------------+
| [IMAGE]|
+----------------------------------+
Cambie las restricciones para alinear de manera diferente dentro de la vista de la imagen.
Puedes hacerlo escalando primero y luego cambiando el tamaño. Lo que hay que mencionar aquí es que estaba condicionado por la altura. Quiero decir, tenía que tener la imagen de 34 píxeles de alto y sin importar el ancho.
Por lo tanto, obtenga la relación entre la altura del contenido real y la altura de la vista (34 px) y luego amplíe el ancho también.
Así es como lo hice:
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];
Espero que esto ayude.
Sé que este es un hilo viejo, pero pensé en compartir lo que hice para cambiar fácilmente la región recortada desde la parte superior a la inferior de la vista de imagen en Interface Builder, en caso de que alguien tuviera el mismo problema que yo. Tuve un UIImageView que llenó la Vista de mi ViewController e intentaba que la parte superior se mantuviera igual, independientemente del tamaño de la pantalla del dispositivo.
Apliqué el factor de forma retina 4 (Editor-> Aplicar factor de forma Retina 4).
Clavé la altura y el ancho.
Ahora, cuando la pantalla cambia de tamaño, el UIImageView es en realidad del mismo tamaño, y el controlador de vista simplemente recorta lo que está fuera de la pantalla. El origen del marco se mantiene en 0,0, por lo que se recortan la parte inferior y la derecha de la imagen, no la parte superior.
Espero que esto ayude.
Si usa Storyboards, esto se puede lograr con restricciones ...
Primero, una UIView con el marco / restricciones finales deseados. Agregue un UIImageView a UIView. Establezca el modo de contenido en Relleno de aspecto. Haz que el marco UIImageView sea la misma relación que la imagen (esto evita advertencias del guion gráfico más adelante). Fije los lados a la UIView usando restricciones estándar. Fije la parte superior O inferior (dependiendo de dónde lo quiera alinear) con la UIView utilizando restricciones estándar. Finalmente agregue una restricción de relación de aspecto al UIImageView (asegurándose de que la relación sea la imagen).
Usé UIImageViewAligned para cambiar la alineación de la imagen gracias al desarrollador
[EDITAR - este código es un poco mohoso desde 2011 y todo, pero incorporé mods de @ ArtOfWarefare]
No puedes hacer esto con UIImageView. Creé una subclase MyImageView
simple MyImageView
que contiene un UIImageView. Código a continuación.
// MyImageView.h
#import <UIKit/UIKit.h>
@interface MyImageView : UIView {
UIImageView *_imageView;
}
@property (nonatomic, assign) UIImage *image;
@end
y
// 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