dla mojego UIImageView wybieram Aspect Fit (InterfaceBuilder), ale jak mogę zmienić wyrównanie w pionie?
dla mojego UIImageView wybieram Aspect Fit (InterfaceBuilder), ale jak mogę zmienić wyrównanie w pionie?
Odpowiedzi:
[EDYTUJ - ten kod jest trochę spleśniały, istota z 2011 r. I wszystkie oprócz mnie włączone mody @ ArtOfWarefare]
Nie możesz tego zrobić w / UIImageView. Utworzyłem prostą podklasę UIView, MyImageView
która zawiera UIImageView. Kod poniżej.
// MyImageView.h
#import <UIKit/UIKit.h>
@interface MyImageView : UIView {
UIImageView *_imageView;
}
@property (nonatomic, assign) UIImage *image;
@end
i
// 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
(ja w zasadzie skopiowaniu initWithFrame
ale otrzymuje [super initWithFrame:]
z [super initWithCoder:]
) i 2 - dodałem w kolejce if (!self.image) return;
do layoutSubviews
tak, że nie będzie katastrofy z nieprawidłowej geometrii jeżeli ISN obraz” t przypisane, gdy jest wywołane. Z tymi dwoma małymi zmianami działa niesamowicie.
dealloc
metoda musi zostać usunięta.
Jeśli używasz scenorysów, można to osiągnąć za pomocą ograniczeń ...
Najpierw UIView z żądaną ostateczną klatką / ograniczeniami. Dodaj UIImageView do UIView. Ustaw contentMode na Aspect Fill. Spraw, aby ramka UIImageView miała ten sam współczynnik co obraz (pozwala to uniknąć późniejszych ostrzeżeń Storyboard). Przypnij boki do UIView, używając standardowych wiązań. Przypnij górę LUB dół (w zależności od tego, gdzie chcesz ją wyrównać) do UIView, używając standardowych ograniczeń. Na koniec dodaj ograniczenie współczynnika proporcji do UIImageView (upewniając się, że współczynnik jest taki jak obraz).
Jest to trochę trudne, ponieważ nie ma opcji ustawiania dalszych reguł wyrównania, jeśli już wybrałeś tryb zawartości ( .scaleAspectFit
).
Ale oto obejście tego problemu:
Najpierw musisz jawnie zmienić rozmiar obrazu źródłowego, obliczając wymiary (jeśli byłby w UIImageView
with 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()
}
}
Następnie wystarczy wywołać tę funkcję na oryginalnym obrazie, przekazując ramkę imageView i przypisując wynik do swojej UIImageView.image
właściwości. Upewnij się również, że ustawiłeś contentMode
tutaj pożądany imageView ( lub nawet w Interface Builder )!
let image = UIImage(named: "MySourceImage")
imageView.image = image?.aspectFitImage(inRect: imageView.frame)
imageView.contentMode = .left
Spróbuj ustawić:
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = YES;
To zadziałało dla mnie.
Użyłem UIImageViewAligned do zmiany wyrównania obrazu dzięki deweloperowi
Wiem, że to stary wątek, ale pomyślałem, że podzielę się tym, co zrobiłem, aby łatwo zmienić przycięty region z góry na dół widoku obrazu w Interface Builder, na wypadek, gdyby ktoś miał ten sam problem, co ja. Miałem UIImageView, który wypełnił widok mojego ViewController i próbowałem, aby górna część pozostała taka sama, niezależnie od rozmiaru ekranu urządzenia.
Zastosowałem współczynnik kształtu siatkówki 4 (Edytor-> Zastosuj współczynnik kształtu Retina 4).
Przypiąłem wysokość i szerokość.
Teraz, gdy ekran zmienia rozmiar, UIImageView ma w rzeczywistości ten sam rozmiar, a kontroler widoku po prostu przycina to, co jest poza ekranem. Początek ramki pozostaje na 0,0, więc dolna i prawa część obrazu jest przycinana, a nie górna.
Mam nadzieję że to pomoże.
Możesz to zrobić, najpierw skalując, a następnie zmieniając rozmiar. Warto tutaj wspomnieć, że byłem uwarunkowany wzrostem. Chodzi mi o to, że musiałem mieć obraz o wysokości 34 pikseli i bez względu na szerokość.
Zatem uzyskaj stosunek między rzeczywistą wysokością treści a wysokością widoku (34 piksele), a następnie skaluj również szerokość.
Oto jak to zrobiłem:
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];
Mam nadzieję że to pomoże.
Doszedłem do następującego rozwiązania:
UIImageView
tryb treści na top
:imageView.contentMode = .top
Aby załadować i zmienić rozmiar obrazu, używam Kingfishera :
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)])
Rozwiązałem to, podklasując UIImageView i zastępując metodę setImage:. Podklasa najpierw zapisze swoje oryginalne wartości pochodzenia i rozmiaru, aby mogła użyć oryginalnego rozmiaru zestawu jako obwiedni.
Ustawiłem tryb treści na UIViewContentModeAspectFit. Wewnątrz setImage: chwyciłem stosunek szerokości do wysokości obrazu, a następnie zmieniłem rozmiar widoku obrazu, aby dopasować go do tego samego współczynnika co obraz. Po zmianie rozmiaru dostosowałem właściwości klatki, aby ustawić widok obrazu w tym samym miejscu, w którym był wcześniej, a następnie wywołałem super setImage :.
Powoduje to, że widok obrazu, którego ramka jest dopasowana dokładnie do obrazu, działa tak, że dopasowanie proporcji działa, a właściwości ramki widoku obrazu robią duże wrażenie, umieszczając widok obrazu tam, gdzie powinien, aby uzyskać ten sam efekt.
Oto kod, którego użyłem:
Po pierwsze, i ogólnie uważam, że jest to całkiem przydatne, jest kategorią w UIView, która ułatwia ustawianie właściwości ramki w widoku za pomocą właściwości takich jak left, right, top, bottom, width, height itp.
@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
To jest podklasa UIImageView. Nie jest w pełni przetestowany, ale powinien przekazać pomysł. Można to rozszerzyć, aby ustawić własne nowe tryby wyrównania.
@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
Jeśli chcesz osiągnąć aspekt, dopasuj i pozbądź się pustych przestrzeni
Nie zapomnij usunąć ograniczenia szerokości widoku obrazu ze scenorysu i ciesz się
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()
}}
Aby wyrównać obraz w celu dopasowania, użyj układu automatycznego. Przykładowy obraz wyrównany do prawej po skalowaniu do dopasowania w UIImageView:
myUIImageView.contentMode = .ScaleAspectFit
myUIImageView.translatesAutoresizingMaskIntoConstraints = false
myUIImageView.image = UIImage(named:"pizza.png")
Twój skalowany obraz z dopasowaniem proporcji jest teraz wyrównany do prawej w UIImageView
+----------------------------------+
| [IMAGE]|
+----------------------------------+
Zmień ograniczenia, aby wyrównać je inaczej w widoku obrazu.