para mi UIImageView, elijo Aspect Fit (InterfaceBuilder), pero ¿cómo puedo cambiar la alineación vertical?
para mi UIImageView, elijo Aspect Fit (InterfaceBuilder), pero ¿cómo puedo cambiar la alineación vertical?
Respuestas:
[EDITAR: este código es un poco mohoso al ser de 2011 y todos, excepto yo, incorporé las modificaciones de @ ArtOfWarefare]
No puede hacer esto con UIImageView. Creé una subclase UIView 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
initWithCoder
(básicamente copié el suyo initWithFrame
pero reemplacé el [super initWithFrame:]
con [super initWithCoder:]
) y 2 - agregué una línea if (!self.image) return;
para layoutSubviews
que no se bloqueara con geometría no válida si una imagen no es ' t asignado cuando se llama. Con estos dos pequeños cambios funciona de maravilla.
dealloc
método debe eliminarse.
Si usa Storyboards, esto se puede lograr con restricciones ...
En primer lugar, una UIView con el marco / restricciones finales deseados. Agregue un UIImageView a UIView. Establezca contentMode en Relleno de aspecto. Haga que el marco de UIImageView tenga la misma proporción que la imagen (esto evita cualquier advertencia de Storyboard más adelante). Fije los lados a la UIView usando restricciones estándar. Fije la parte superior O inferior (dependiendo de dónde desee que se alinee) a UIView usando restricciones estándar. Finalmente, agregue una restricción de relación de aspecto a UIImageView (asegurándose de que la relación sea la imagen).
Este 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 debe cambiar el tamaño de la imagen de origen de forma explícita calculando las dimensiones (si fuera UIImageView
con 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()
}
}
Luego, simplemente necesita llamar a esta función en su imagen original pasando el marco de su imageView y asignar el resultado a su UIImageView.image
propiedad. Además, asegúrese de configurar su imageView deseado contentMode
aquí ( o incluso en el Interface Builder ).
let image = UIImage(named: "MySourceImage")
imageView.image = image?.aspectFitImage(inRect: imageView.frame)
imageView.contentMode = .left
Intente configurar:
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
Esto funcionó para mí.
Usé UIImageViewAligned para cambiar la alineación de la imagen gracias al desarrollador
Sé que este es un hilo antiguo, pero pensé en compartir lo que hice para cambiar fácilmente la región recortada de 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. Tenía un UIImageView que llenaba la Vista de mi ViewController y estaba tratando de que la parte superior permaneciera 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 solo recorta lo que está fuera de la pantalla. El origen del marco permanece en 0,0, por lo que la parte inferior y derecha de la imagen se recortan, no la parte superior.
Espero que esto ayude.
Puede hacerlo primero escalando y luego cambiando el tamaño. Lo que debo mencionar aquí es que estaba condicionado por la altura. Quiero decir, tenía que tener la imagen de 34px de alto y sin importar el ancho.
Entonces, obtenga la relación entre la altura real del contenido y la altura de la vista (34 px) y luego escale 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.
Llegué a la siguiente solución:
UIImageView
modo de contenido en top
:imageView.contentMode = .top
Para cargar y cambiar el tamaño de la imagen utilizo 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)])
Resolví esto subclasificando UIImageView y anulando el método setImage :. La subclase almacenaría primero sus valores originales de origen y tamaño para poder usar el tamaño del conjunto original como cuadro delimitador.
Configuré el modo de contenido en UIViewContentModeAspectFit. Dentro de setImage: tomé la relación de ancho a alto de la imagen y luego cambié el tamaño de la vista de la imagen para que se ajustara 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 super 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 la vista de imagen están haciendo el trabajo pesado al colocar la vista de imagen donde debería estar para obtener el mismo efecto.
Aquí hay un código que usé:
En primer lugar, y lo encuentro bastante útil en general, es una categoría en UIView que facilita la configuración de las propiedades del marco en una vista a través de propiedades como izquierda, derecha, arriba, abajo, ancho, alto, etc.
@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 debería transmitir la idea. Esto podría ampliarse para establecer sus propios modos nuevos de alineación.
@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
Si necesita lograr AspectFit y eliminar los espacios vacíos
No olvide eliminar la restricción de ancho de su vista de imagen del guión gráfico y disfrute
class 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()
}}
Para alinear una imagen a escala, utilice el diseño automático. Ejemplo de imagen alineada a la derecha después de escalar para ajustar en UIImageView:
myUIImageView.contentMode = .ScaleAspectFit
myUIImageView.translatesAutoresizingMaskIntoConstraints = false
myUIImageView.image = UIImage(named:"pizza.png")
Su imagen escalada de ajuste de aspecto ahora está alineada a la derecha en UIImageView
+----------------------------------+
| [IMAGE]|
+----------------------------------+
Cambie las restricciones para alinear de manera diferente dentro de la vista de imagen.