Für mein UIImageView wähle ich Aspect Fit (InterfaceBuilder), aber wie kann ich die vertikale Ausrichtung ändern?
Für mein UIImageView wähle ich Aspect Fit (InterfaceBuilder), aber wie kann ich die vertikale Ausrichtung ändern?
Antworten:
[BEARBEITEN - dieser Code ist ein bisschen schimmelig aus dem Jahr 2011 und alle außer ich habe die Mods von @ ArtOfWarefare integriert]
Sie können dies nicht mit UIImageView tun. Ich habe eine einfache UIView-Unterklasse erstellt MyImageView
, die eine UIImageView enthält. Code unten.
// MyImageView.h
#import <UIKit/UIKit.h>
@interface MyImageView : UIView {
UIImageView *_imageView;
}
@property (nonatomic, assign) UIImage *image;
@end
und
// 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
(I grundsätzlich kopieren Sie initWithFrame
aber ersetzt die [super initWithFrame:]
mit [super initWithCoder:]
) und 2 - I in einer Linie hinzugefügt , if (!self.image) return;
um layoutSubviews
so , dass es nicht mit ungültiger Geometrie , wenn ein Bild isn abstürze würde‘ t zugewiesen, wenn es aufgerufen wird. Mit diesen beiden kleinen Änderungen funktioniert es erstaunlich.
dealloc
Methode entfernt werden.
Wenn Sie Storyboards verwenden, kann dies mit Einschränkungen erreicht werden ...
Zunächst ein UIView mit dem gewünschten endgültigen Frame / den gewünschten Einschränkungen. Fügen Sie der UIView eine UIImageView hinzu. Stellen Sie den contentMode auf Aspect Fill ein. Stellen Sie sicher, dass der UIImageView-Frame das gleiche Verhältnis wie das Bild hat (dies vermeidet später Storyboard-Warnungen). Befestigen Sie die Seiten mit Standardbeschränkungen an der UIView. Befestigen Sie das obere ODER untere Ende (je nachdem, wo Sie es ausrichten möchten) mit Standardbeschränkungen an der UIView. Fügen Sie der UIImageView schließlich eine Einschränkung des Seitenverhältnisses hinzu (stellen Sie sicher, dass das Verhältnis das Bild ist).
Dies ist etwas schwierig, da es keine Möglichkeit gibt, weitere Ausrichtungsregeln festzulegen, wenn Sie bereits einen Inhaltsmodus ausgewählt haben ( .scaleAspectFit
).
Aber hier ist eine Problemumgehung:
Zuerst müssen Sie die Größe Ihres Quellbilds explizit ändern, indem Sie die Abmessungen berechnen (wenn es in einem UIImageView
mit wäre 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()
}
}
Dann müssen Sie diese Funktion einfach für Ihr Originalbild aufrufen, indem Sie den Rahmen Ihrer imageView übergeben und das Ergebnis Ihrer UIImageView.image
Eigenschaft zuweisen . Stellen Sie außerdem sicher, dass Sie contentMode
hier ( oder sogar im Interface Builder ) die gewünschte Bildansicht einstellen !
let image = UIImage(named: "MySourceImage")
imageView.image = image?.aspectFitImage(inRect: imageView.frame)
imageView.contentMode = .left
Versuchen Sie die Einstellung:
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
Das hat bei mir funktioniert.
Ich habe UIImageViewAligned verwendet, um die Ausrichtung des Bildes dank des Entwicklers zu ändern
Ich weiß, dass dies ein alter Thread ist, aber ich dachte, ich würde mitteilen, was ich getan habe, um den abgeschnittenen Bereich in Interface Builder einfach vom oberen zum unteren Rand der Bildansicht zu ändern, falls jemand das gleiche Problem hatte wie ich. Ich hatte eine UIImageView, die die Ansicht meines ViewControllers füllte, und versuchte, die Oberseite unabhängig von der Größe des Gerätebildschirms gleich zu halten.
Ich habe den Retina 4-Formfaktor angewendet (Editor-> Retina 4-Formfaktor anwenden).
Ich habe die Höhe und Breite festgehalten.
Wenn sich die Größe des Bildschirms ändert, hat UIImageView tatsächlich dieselbe Größe, und der Ansichts-Controller schneidet nur das ab, was sich außerhalb des Bildschirms befindet. Der Rahmenursprung bleibt bei 0,0, sodass die untere und rechte Seite des Bildes abgeschnitten werden und nicht die obere.
Hoffe das hilft.
Sie können dies tun, indem Sie zuerst skalieren und dann die Größe ändern. Hier ist zu erwähnen, dass ich von der Größe abhängig war. Ich meine, ich musste das Bild von 34px hoch und egal wie breit haben.
Ermitteln Sie also das Verhältnis zwischen der tatsächlichen Höhe des Inhalts und der Höhe der Ansicht (34 px) und skalieren Sie dann auch die Breite.
So habe ich es gemacht:
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];
Hoffe das hilft.
Ich bin zu folgender Lösung gekommen:
UIImageView
Inhaltsmodus auf top
:imageView.contentMode = .top
Zum Laden und Ändern der Bildgröße verwende ich 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)])
Ich habe dies gelöst, indem ich UIImageView unterklassifiziert und die setImage: -Methode überschrieben habe. Die Unterklasse speichert zuerst ihre ursprünglichen Werte für Ursprung und Größe, damit sie die ursprüngliche Satzgröße als Begrenzungsrahmen verwenden kann.
Ich habe den Inhaltsmodus auf UIViewContentModeAspectFit eingestellt. Innerhalb von setImage: Ich habe das Verhältnis von Bildbreite zu Bildhöhe erfasst und dann die Bildansicht so angepasst, dass sie dem gleichen Verhältnis wie das Bild entspricht. Nach der Größenänderung habe ich meine Rahmeneigenschaften angepasst, um die Bildansicht an derselben Stelle wie zuvor festzulegen, und dann das Super-SetImage: aufgerufen.
Dies führt zu einer Bildansicht, deren Rahmen genau an das Bild angepasst ist, sodass die Aspektanpassung funktioniert und die Rahmeneigenschaften der Bildansicht die Bildansicht an die Stelle bringen, an der sie sein sollte, um den gleichen Effekt zu erzielen.
Hier ist ein Code, den ich verwendet habe:
Erstens, und ich finde es im Allgemeinen ziemlich nützlich, ist eine Kategorie in UIView, die es einfach macht, Rahmeneigenschaften in einer Ansicht über Eigenschaften wie links, rechts, oben, unten, Breite, Höhe usw. festzulegen.
@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
Dies ist die Unterklasse von UIImageView. Es ist nicht vollständig getestet, sollte aber die Idee vermitteln. Dies könnte erweitert werden, um Ihre eigenen neuen Modi für die Ausrichtung festzulegen.
@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
Wenn Sie aspectFit erreichen und leere Räume entfernen müssen
Vergessen Sie nicht, die Breitenbeschränkung Ihrer Bildansicht aus dem Storyboard zu entfernen und zu genießen
Klasse 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()
}}
Verwenden Sie das automatische Layout, um ein maßstabsgetreues Bild auszurichten. Beispiel für ein rechtsbündiges Bild nach dem Anpassen in UIImageView:
myUIImageView.contentMode = .ScaleAspectFit
myUIImageView.translatesAutoresizingMaskIntoConstraints = false
myUIImageView.image = UIImage(named:"pizza.png")
Ihr skaliertes Bild mit Aspektanpassung ist jetzt in der UIImageView rechtsbündig ausgerichtet
+----------------------------------+
| [IMAGE]|
+----------------------------------+
Ändern Sie die Einschränkungen so, dass sie in der Bildansicht unterschiedlich ausgerichtet werden.